Roles/kde: remove patches
All of this patches are in 6.3, so they're not needed anymore
This commit is contained in:
parent
789157e3bf
commit
5640408d9f
10 changed files with 0 additions and 2973 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1,41 +0,0 @@
|
|||
diff --git a/src/plugins/private/expolayout.cpp b/src/plugins/private/expolayout.cpp
|
||||
index 52e8bd6616..d4f2a41acc 100644
|
||||
--- a/src/plugins/private/expolayout.cpp
|
||||
+++ b/src/plugins/private/expolayout.cpp
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "expolayout.h"
|
||||
|
||||
+#include <QQmlProperty>
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
#include <tuple>
|
||||
@@ -41,6 +42,12 @@ ExpoCell::~ExpoCell()
|
||||
void ExpoCell::componentComplete()
|
||||
{
|
||||
QQuickItem::componentComplete();
|
||||
+
|
||||
+ QQmlProperty xProperty(this, "Kirigami.ScenePosition.x", qmlContext(this));
|
||||
+ xProperty.connectNotifySignal(this, SLOT(updateContentItemGeometry()));
|
||||
+ QQmlProperty yProperty(this, "Kirigami.ScenePosition.y", qmlContext(this));
|
||||
+ yProperty.connectNotifySignal(this, SLOT(updateContentItemGeometry()));
|
||||
+
|
||||
updateContentItemGeometry();
|
||||
}
|
||||
|
||||
diff --git a/src/plugins/private/expolayout.h b/src/plugins/private/expolayout.h
|
||||
index 0d4f9d5cde..d980c2aabb 100644
|
||||
--- a/src/plugins/private/expolayout.h
|
||||
+++ b/src/plugins/private/expolayout.h
|
||||
@@ -264,8 +264,10 @@ Q_SIGNALS:
|
||||
void persistentKeyChanged();
|
||||
void bottomMarginChanged();
|
||||
|
||||
-private:
|
||||
+private Q_SLOTS:
|
||||
void updateContentItemGeometry();
|
||||
+
|
||||
+private:
|
||||
void updateLayout();
|
||||
|
||||
QString m_persistentKey;
|
||||
|
|
@ -1,753 +0,0 @@
|
|||
diff --git a/src/plugins/zoom/CMakeLists.txt b/src/plugins/zoom/CMakeLists.txt
|
||||
index c27bdbbb2d..b5fb343e17 100644
|
||||
--- a/src/plugins/zoom/CMakeLists.txt
|
||||
+++ b/src/plugins/zoom/CMakeLists.txt
|
||||
@@ -4,6 +4,7 @@
|
||||
set(zoom_SOURCES
|
||||
main.cpp
|
||||
zoom.cpp
|
||||
+ zoom.qrc
|
||||
)
|
||||
|
||||
if (HAVE_ACCESSIBILITY)
|
||||
diff --git a/src/plugins/zoom/shaders/pixelgrid.frag b/src/plugins/zoom/shaders/pixelgrid.frag
|
||||
new file mode 100644
|
||||
index 0000000000..1e9ee9431f
|
||||
--- /dev/null
|
||||
+++ b/src/plugins/zoom/shaders/pixelgrid.frag
|
||||
@@ -0,0 +1,25 @@
|
||||
+#include "colormanagement.glsl"
|
||||
+
|
||||
+uniform sampler2D sampler;
|
||||
+uniform int textureWidth;
|
||||
+uniform int textureHeight;
|
||||
+
|
||||
+varying vec2 texcoord0;
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ vec2 texSize = vec2(textureWidth, textureHeight);
|
||||
+ vec2 samplePosition = texcoord0 * texSize;
|
||||
+ vec2 pixelCenter = floor(samplePosition) + vec2(0.5);
|
||||
+ vec2 pixelCenterDistance = abs(samplePosition - pixelCenter);
|
||||
+
|
||||
+ vec4 tex;
|
||||
+ if (pixelCenterDistance.x > 0.4 || pixelCenterDistance.y > 0.4) {
|
||||
+ tex = vec4(0, 0, 0, 1);
|
||||
+ } else {
|
||||
+ tex = texture2D(sampler, pixelCenter / texSize);
|
||||
+ }
|
||||
+
|
||||
+ tex = sourceEncodingToNitsInDestinationColorspace(tex);
|
||||
+ gl_FragColor = nitsToDestinationEncoding(tex);
|
||||
+}
|
||||
diff --git a/src/plugins/zoom/shaders/pixelgrid_core.frag b/src/plugins/zoom/shaders/pixelgrid_core.frag
|
||||
new file mode 100644
|
||||
index 0000000000..a1cc7f27f2
|
||||
--- /dev/null
|
||||
+++ b/src/plugins/zoom/shaders/pixelgrid_core.frag
|
||||
@@ -0,0 +1,24 @@
|
||||
+#version 140
|
||||
+
|
||||
+#include "colormanagement.glsl"
|
||||
+
|
||||
+uniform sampler2D sampler;
|
||||
+uniform int textureWidth;
|
||||
+uniform int textureHeight;
|
||||
+
|
||||
+in vec2 texcoord0;
|
||||
+
|
||||
+out vec4 fragColor;
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ vec2 texSize = vec2(textureWidth, textureHeight);
|
||||
+ vec2 samplePosition = texcoord0 * texSize;
|
||||
+ vec2 pixelCenter = floor(samplePosition) + vec2(0.5);
|
||||
+ vec2 pixelCenterDistance = abs(samplePosition - pixelCenter);
|
||||
+
|
||||
+ float t = smoothstep(0.4, 0.5, max(pixelCenterDistance.x, pixelCenterDistance.y));
|
||||
+ vec4 tex = mix(texture(sampler, pixelCenter / texSize), vec4(0, 0, 0, 1), t);
|
||||
+ tex = sourceEncodingToNitsInDestinationColorspace(tex);
|
||||
+ fragColor = nitsToDestinationEncoding(tex);
|
||||
+}
|
||||
diff --git a/src/plugins/zoom/ui_zoom_config.h b/src/plugins/zoom/ui_zoom_config.h
|
||||
new file mode 100644
|
||||
index 0000000000..7e5944a902
|
||||
--- /dev/null
|
||||
+++ b/src/plugins/zoom/ui_zoom_config.h
|
||||
@@ -0,0 +1,195 @@
|
||||
+/********************************************************************************
|
||||
+** Form generated from reading UI file 'zoom_config.ui'
|
||||
+**
|
||||
+** Created by: Qt User Interface Compiler version 6.8.1
|
||||
+**
|
||||
+** WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
+********************************************************************************/
|
||||
+
|
||||
+#ifndef UI_ZOOM_CONFIG_H
|
||||
+#define UI_ZOOM_CONFIG_H
|
||||
+
|
||||
+#include <QtCore/QVariant>
|
||||
+#include <QtWidgets/QApplication>
|
||||
+#include <QtWidgets/QCheckBox>
|
||||
+#include <QtWidgets/QComboBox>
|
||||
+#include <QtWidgets/QDoubleSpinBox>
|
||||
+#include <QtWidgets/QGridLayout>
|
||||
+#include <QtWidgets/QGroupBox>
|
||||
+#include <QtWidgets/QHBoxLayout>
|
||||
+#include <QtWidgets/QLabel>
|
||||
+#include <QtWidgets/QVBoxLayout>
|
||||
+#include <QtWidgets/QWidget>
|
||||
+#include "kshortcutseditor.h"
|
||||
+
|
||||
+namespace KWin {
|
||||
+
|
||||
+class Ui_ZoomEffectConfigForm
|
||||
+{
|
||||
+public:
|
||||
+ QVBoxLayout *verticalLayout_2;
|
||||
+ QGroupBox *groupSize;
|
||||
+ QHBoxLayout *horizontalLayout;
|
||||
+ QGridLayout *gridLayout;
|
||||
+ QLabel *label;
|
||||
+ QDoubleSpinBox *kcfg_ZoomFactor;
|
||||
+ QCheckBox *kcfg_EnableFocusTracking;
|
||||
+ QCheckBox *kcfg_EnableTextCaretTracking;
|
||||
+ QLabel *label_2;
|
||||
+ QComboBox *kcfg_MousePointer;
|
||||
+ QComboBox *kcfg_MouseTracking;
|
||||
+ QLabel *label_3;
|
||||
+ KShortcutsEditor *editor;
|
||||
+
|
||||
+ void setupUi(QWidget *KWin__ZoomEffectConfigForm)
|
||||
+ {
|
||||
+ if (KWin__ZoomEffectConfigForm->objectName().isEmpty())
|
||||
+ KWin__ZoomEffectConfigForm->setObjectName("KWin__ZoomEffectConfigForm");
|
||||
+ KWin__ZoomEffectConfigForm->resize(304, 288);
|
||||
+ verticalLayout_2 = new QVBoxLayout(KWin__ZoomEffectConfigForm);
|
||||
+ verticalLayout_2->setObjectName("verticalLayout_2");
|
||||
+ groupSize = new QGroupBox(KWin__ZoomEffectConfigForm);
|
||||
+ groupSize->setObjectName("groupSize");
|
||||
+ horizontalLayout = new QHBoxLayout(groupSize);
|
||||
+ horizontalLayout->setObjectName("horizontalLayout");
|
||||
+ gridLayout = new QGridLayout();
|
||||
+ gridLayout->setObjectName("gridLayout");
|
||||
+ label = new QLabel(groupSize);
|
||||
+ label->setObjectName("label");
|
||||
+ label->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
||||
+
|
||||
+ gridLayout->addWidget(label, 0, 0, 1, 1);
|
||||
+
|
||||
+ kcfg_ZoomFactor = new QDoubleSpinBox(groupSize);
|
||||
+ kcfg_ZoomFactor->setObjectName("kcfg_ZoomFactor");
|
||||
+ kcfg_ZoomFactor->setDecimals(2);
|
||||
+ kcfg_ZoomFactor->setMaximum(9999.000000000000000);
|
||||
+ kcfg_ZoomFactor->setSingleStep(0.050000000000000);
|
||||
+ kcfg_ZoomFactor->setValue(1.250000000000000);
|
||||
+
|
||||
+ gridLayout->addWidget(kcfg_ZoomFactor, 0, 1, 1, 1);
|
||||
+
|
||||
+ kcfg_EnableFocusTracking = new QCheckBox(groupSize);
|
||||
+ kcfg_EnableFocusTracking->setObjectName("kcfg_EnableFocusTracking");
|
||||
+
|
||||
+ gridLayout->addWidget(kcfg_EnableFocusTracking, 4, 0, 1, 2);
|
||||
+
|
||||
+ kcfg_EnableTextCaretTracking = new QCheckBox(groupSize);
|
||||
+ kcfg_EnableTextCaretTracking->setObjectName("kcfg_EnableTextCaretTracking");
|
||||
+
|
||||
+ gridLayout->addWidget(kcfg_EnableTextCaretTracking, 5, 0, 1, 2);
|
||||
+
|
||||
+ label_2 = new QLabel(groupSize);
|
||||
+ label_2->setObjectName("label_2");
|
||||
+ label_2->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
||||
+
|
||||
+ gridLayout->addWidget(label_2, 2, 0, 1, 1);
|
||||
+
|
||||
+ kcfg_MousePointer = new QComboBox(groupSize);
|
||||
+ kcfg_MousePointer->addItem(QString());
|
||||
+ kcfg_MousePointer->addItem(QString());
|
||||
+ kcfg_MousePointer->addItem(QString());
|
||||
+ kcfg_MousePointer->setObjectName("kcfg_MousePointer");
|
||||
+
|
||||
+ gridLayout->addWidget(kcfg_MousePointer, 2, 1, 1, 1);
|
||||
+
|
||||
+ kcfg_MouseTracking = new QComboBox(groupSize);
|
||||
+ kcfg_MouseTracking->addItem(QString());
|
||||
+ kcfg_MouseTracking->addItem(QString());
|
||||
+ kcfg_MouseTracking->addItem(QString());
|
||||
+ kcfg_MouseTracking->addItem(QString());
|
||||
+ kcfg_MouseTracking->setObjectName("kcfg_MouseTracking");
|
||||
+
|
||||
+ gridLayout->addWidget(kcfg_MouseTracking, 3, 1, 1, 1);
|
||||
+
|
||||
+ label_3 = new QLabel(groupSize);
|
||||
+ label_3->setObjectName("label_3");
|
||||
+ label_3->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
||||
+
|
||||
+ gridLayout->addWidget(label_3, 3, 0, 1, 1);
|
||||
+
|
||||
+
|
||||
+ horizontalLayout->addLayout(gridLayout);
|
||||
+
|
||||
+
|
||||
+ verticalLayout_2->addWidget(groupSize);
|
||||
+
|
||||
+ editor = new KShortcutsEditor(KWin__ZoomEffectConfigForm);
|
||||
+ editor->setObjectName("editor");
|
||||
+ QSizePolicy sizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Expanding);
|
||||
+ sizePolicy.setHorizontalStretch(0);
|
||||
+ sizePolicy.setVerticalStretch(0);
|
||||
+ sizePolicy.setHeightForWidth(editor->sizePolicy().hasHeightForWidth());
|
||||
+ editor->setSizePolicy(sizePolicy);
|
||||
+ editor->setActionTypes(KShortcutsEditor::GlobalAction);
|
||||
+
|
||||
+ verticalLayout_2->addWidget(editor);
|
||||
+
|
||||
+#if QT_CONFIG(shortcut)
|
||||
+ label->setBuddy(kcfg_ZoomFactor);
|
||||
+ label_2->setBuddy(kcfg_MousePointer);
|
||||
+ label_3->setBuddy(kcfg_MouseTracking);
|
||||
+#endif // QT_CONFIG(shortcut)
|
||||
+ QWidget::setTabOrder(kcfg_ZoomFactor, kcfg_MousePointer);
|
||||
+ QWidget::setTabOrder(kcfg_MousePointer, kcfg_MouseTracking);
|
||||
+ QWidget::setTabOrder(kcfg_MouseTracking, kcfg_EnableFocusTracking);
|
||||
+ QWidget::setTabOrder(kcfg_EnableFocusTracking, kcfg_EnableTextCaretTracking);
|
||||
+
|
||||
+ retranslateUi(KWin__ZoomEffectConfigForm);
|
||||
+
|
||||
+ QMetaObject::connectSlotsByName(KWin__ZoomEffectConfigForm);
|
||||
+ } // setupUi
|
||||
+
|
||||
+ void retranslateUi(QWidget *KWin__ZoomEffectConfigForm)
|
||||
+ {
|
||||
+ groupSize->setTitle(QString());
|
||||
+#if QT_CONFIG(whatsthis)
|
||||
+ label->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "On zoom-in and zoom-out change the zoom by the defined zoom-factor.", nullptr));
|
||||
+#endif // QT_CONFIG(whatsthis)
|
||||
+ label->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Zoom Factor:", nullptr));
|
||||
+#if QT_CONFIG(whatsthis)
|
||||
+ kcfg_ZoomFactor->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "On zoom-in and zoom-out change the zoom by the defined zoom-factor.", nullptr));
|
||||
+#endif // QT_CONFIG(whatsthis)
|
||||
+ kcfg_ZoomFactor->setSuffix(QString());
|
||||
+#if QT_CONFIG(tooltip)
|
||||
+ kcfg_EnableFocusTracking->setToolTip(QString());
|
||||
+#endif // QT_CONFIG(tooltip)
|
||||
+#if QT_CONFIG(whatsthis)
|
||||
+ kcfg_EnableFocusTracking->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable tracking of the focused location. This needs QAccessible to be enabled per application (\"export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1\").", nullptr));
|
||||
+#endif // QT_CONFIG(whatsthis)
|
||||
+ kcfg_EnableFocusTracking->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable Focus Tracking", nullptr));
|
||||
+#if QT_CONFIG(whatsthis)
|
||||
+ kcfg_EnableTextCaretTracking->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable tracking of the text cursor. This needs QAccessible to be enabled per application (\"export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1\").", nullptr));
|
||||
+#endif // QT_CONFIG(whatsthis)
|
||||
+ kcfg_EnableTextCaretTracking->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable Text Cursor Tracking", nullptr));
|
||||
+ label_2->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Mouse Pointer:", nullptr));
|
||||
+ kcfg_MousePointer->setItemText(0, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Scale", nullptr));
|
||||
+ kcfg_MousePointer->setItemText(1, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Keep", nullptr));
|
||||
+ kcfg_MousePointer->setItemText(2, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Hide", nullptr));
|
||||
+
|
||||
+#if QT_CONFIG(whatsthis)
|
||||
+ kcfg_MousePointer->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Visibility of the mouse-pointer.", nullptr));
|
||||
+#endif // QT_CONFIG(whatsthis)
|
||||
+ kcfg_MouseTracking->setItemText(0, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Proportional", nullptr));
|
||||
+ kcfg_MouseTracking->setItemText(1, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Centered", nullptr));
|
||||
+ kcfg_MouseTracking->setItemText(2, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Push", nullptr));
|
||||
+ kcfg_MouseTracking->setItemText(3, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Disabled", nullptr));
|
||||
+
|
||||
+#if QT_CONFIG(whatsthis)
|
||||
+ kcfg_MouseTracking->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Track moving of the mouse.", nullptr));
|
||||
+#endif // QT_CONFIG(whatsthis)
|
||||
+ label_3->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Mouse Tracking:", nullptr));
|
||||
+ (void)KWin__ZoomEffectConfigForm;
|
||||
+ } // retranslateUi
|
||||
+
|
||||
+};
|
||||
+
|
||||
+} // namespace KWin
|
||||
+
|
||||
+namespace KWin {
|
||||
+namespace Ui {
|
||||
+ class ZoomEffectConfigForm: public Ui_ZoomEffectConfigForm {};
|
||||
+} // namespace Ui
|
||||
+} // namespace KWin
|
||||
+
|
||||
+#endif // UI_ZOOM_CONFIG_H
|
||||
diff --git a/src/plugins/zoom/zoom.cpp b/src/plugins/zoom/zoom.cpp
|
||||
index a6eb528767..950583c15b 100644
|
||||
--- a/src/plugins/zoom/zoom.cpp
|
||||
+++ b/src/plugins/zoom/zoom.cpp
|
||||
@@ -31,6 +31,12 @@
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
+static void ensureResources()
|
||||
+{
|
||||
+ // Must initialize resources manually because the effect is a static lib.
|
||||
+ Q_INIT_RESOURCE(zoom);
|
||||
+}
|
||||
+
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
@@ -48,6 +54,8 @@ ZoomEffect::ZoomEffect()
|
||||
, moveFactor(20.0)
|
||||
, lastPresentTime(std::chrono::milliseconds::zero())
|
||||
{
|
||||
+ ensureResources();
|
||||
+
|
||||
ZoomConfig::instance(effects->config());
|
||||
QAction *a = nullptr;
|
||||
a = KStandardAction::zoomIn(this, SLOT(zoomIn()), this);
|
||||
@@ -214,6 +222,7 @@ void ZoomEffect::reconfigure(ReconfigureFlags)
|
||||
ZoomConfig::self()->read();
|
||||
// On zoom-in and zoom-out change the zoom by the defined zoom-factor.
|
||||
zoomFactor = std::max(0.1, ZoomConfig::zoomFactor());
|
||||
+ m_pixelGridZoom = ZoomConfig::pixelGridZoom();
|
||||
// Visibility of the mouse-pointer.
|
||||
mousePointer = MousePointerType(ZoomConfig::mousePointer());
|
||||
// Track moving of the mouse.
|
||||
@@ -271,12 +280,10 @@ void ZoomEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseco
|
||||
|
||||
ZoomEffect::OffscreenData *ZoomEffect::ensureOffscreenData(const RenderTarget &renderTarget, const RenderViewport &viewport, Output *screen)
|
||||
{
|
||||
- const QRect rect = viewport.renderRect().toRect();
|
||||
- const qreal devicePixelRatio = viewport.scale();
|
||||
- const QSize nativeSize = (viewport.renderRect().size() * devicePixelRatio).toSize();
|
||||
+ const QSize nativeSize = renderTarget.size();
|
||||
|
||||
OffscreenData &data = m_offscreenData[effects->waylandDisplay() ? screen : nullptr];
|
||||
- data.viewport = rect;
|
||||
+ data.viewport = viewport.renderRect();
|
||||
data.color = renderTarget.colorDescription();
|
||||
|
||||
const GLenum textureFormat = renderTarget.colorDescription() == ColorDescription::sRGB ? GL_RGBA8 : GL_RGBA16F;
|
||||
@@ -290,9 +297,22 @@ ZoomEffect::OffscreenData *ZoomEffect::ensureOffscreenData(const RenderTarget &r
|
||||
data.framebuffer = std::make_unique<GLFramebuffer>(data.texture.get());
|
||||
}
|
||||
|
||||
+ data.texture->setContentTransform(renderTarget.transform());
|
||||
return &data;
|
||||
}
|
||||
|
||||
+GLShader *ZoomEffect::shaderForZoom(double zoom)
|
||||
+{
|
||||
+ if (zoom < m_pixelGridZoom) {
|
||||
+ return ShaderManager::instance()->shader(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
|
||||
+ } else {
|
||||
+ if (!m_pixelGridShader) {
|
||||
+ m_pixelGridShader = ShaderManager::instance()->generateShaderFromFile(ShaderTrait::MapTexture, QString(), QStringLiteral(":/effects/zoom/shaders/pixelgrid.frag"));
|
||||
+ }
|
||||
+ return m_pixelGridShader.get();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen)
|
||||
{
|
||||
OffscreenData *offscreenData = ensureOffscreenData(renderTarget, viewport, screen);
|
||||
@@ -391,7 +411,8 @@ void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewp
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
- auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
|
||||
+ GLShader *shader = shaderForZoom(zoom);
|
||||
+ ShaderManager::instance()->pushShader(shader);
|
||||
for (auto &[screen, offscreen] : m_offscreenData) {
|
||||
QMatrix4x4 matrix;
|
||||
matrix.translate(xTranslation * scale, yTranslation * scale);
|
||||
@@ -399,6 +420,8 @@ void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewp
|
||||
matrix.translate(offscreen.viewport.x() * scale, offscreen.viewport.y() * scale);
|
||||
|
||||
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix() * matrix);
|
||||
+ shader->setUniform(GLShader::IntUniform::TextureWidth, offscreen.texture->width());
|
||||
+ shader->setUniform(GLShader::IntUniform::TextureHeight, offscreen.texture->height());
|
||||
shader->setColorspaceUniforms(offscreen.color, renderTarget.colorDescription(), RenderingIntent::Perceptual);
|
||||
|
||||
offscreen.texture->render(offscreen.viewport.size() * scale);
|
||||
diff --git a/src/plugins/zoom/zoom.h b/src/plugins/zoom/zoom.h
|
||||
index 2a44395d74..1c9abb4b4e 100644
|
||||
--- a/src/plugins/zoom/zoom.h
|
||||
+++ b/src/plugins/zoom/zoom.h
|
||||
@@ -26,6 +26,7 @@ class ZoomAccessibilityIntegration;
|
||||
class GLFramebuffer;
|
||||
class GLTexture;
|
||||
class GLVertexBuffer;
|
||||
+class GLShader;
|
||||
|
||||
class ZoomEffect
|
||||
: public Effect
|
||||
@@ -94,7 +95,7 @@ private:
|
||||
{
|
||||
std::unique_ptr<GLTexture> texture;
|
||||
std::unique_ptr<GLFramebuffer> framebuffer;
|
||||
- QRect viewport;
|
||||
+ QRectF viewport;
|
||||
ColorDescription color = ColorDescription::sRGB;
|
||||
};
|
||||
|
||||
@@ -102,6 +103,8 @@ private:
|
||||
OffscreenData *ensureOffscreenData(const RenderTarget &renderTarget, const RenderViewport &viewport, Output *screen);
|
||||
void markCursorTextureDirty();
|
||||
|
||||
+ GLShader *shaderForZoom(double zoom);
|
||||
+
|
||||
#if HAVE_ACCESSIBILITY
|
||||
ZoomAccessibilityIntegration *m_accessibilityIntegration = nullptr;
|
||||
#endif
|
||||
@@ -136,6 +139,8 @@ private:
|
||||
double moveFactor;
|
||||
std::chrono::milliseconds lastPresentTime;
|
||||
std::map<Output *, OffscreenData> m_offscreenData;
|
||||
+ std::unique_ptr<GLShader> m_pixelGridShader;
|
||||
+ double m_pixelGridZoom;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
diff --git a/src/plugins/zoom/zoom.kcfg b/src/plugins/zoom/zoom.kcfg
|
||||
index 63887e32aa..ed43e225c8 100644
|
||||
--- a/src/plugins/zoom/zoom.kcfg
|
||||
+++ b/src/plugins/zoom/zoom.kcfg
|
||||
@@ -29,5 +29,8 @@
|
||||
<entry name="InitialZoom" type="Double">
|
||||
<default>1.0</default>
|
||||
</entry>
|
||||
+ <entry name="PixelGridZoom" type="Double">
|
||||
+ <default>15.0</default>
|
||||
+ </entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
diff --git a/src/plugins/zoom/zoom.qrc b/src/plugins/zoom/zoom.qrc
|
||||
new file mode 100644
|
||||
index 0000000000..56e7369003
|
||||
--- /dev/null
|
||||
+++ b/src/plugins/zoom/zoom.qrc
|
||||
@@ -0,0 +1,6 @@
|
||||
+<!DOCTYPE RCC><RCC version="1.0">
|
||||
+<qresource prefix="/effects/zoom/">
|
||||
+ <file>shaders/pixelgrid.frag</file>
|
||||
+ <file>shaders/pixelgrid_core.frag</file>
|
||||
+</qresource>
|
||||
+</RCC>
|
||||
diff --git a/src/plugins/zoom/zoom_config.ui b/src/plugins/zoom/zoom_config.ui
|
||||
index 454f9f9161..4b8a5c000e 100644
|
||||
--- a/src/plugins/zoom/zoom_config.ui
|
||||
+++ b/src/plugins/zoom/zoom_config.ui
|
||||
@@ -6,159 +6,157 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
- <width>304</width>
|
||||
- <height>288</height>
|
||||
+ <width>595</width>
|
||||
+ <height>551</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
- <widget class="QGroupBox" name="groupSize">
|
||||
- <property name="title">
|
||||
- <string/>
|
||||
+ <layout class="QFormLayout" name="formLayout">
|
||||
+ <property name="formAlignment">
|
||||
+ <set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||
</property>
|
||||
- <layout class="QHBoxLayout" name="horizontalLayout">
|
||||
- <item>
|
||||
- <layout class="QGridLayout" name="gridLayout">
|
||||
- <item row="0" column="0">
|
||||
- <widget class="QLabel" name="label">
|
||||
- <property name="whatsThis">
|
||||
- <string>On zoom-in and zoom-out change the zoom by the defined zoom-factor.</string>
|
||||
- </property>
|
||||
- <property name="text">
|
||||
- <string>Zoom Factor:</string>
|
||||
- </property>
|
||||
- <property name="alignment">
|
||||
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
- </property>
|
||||
- <property name="buddy">
|
||||
- <cstring>kcfg_ZoomFactor</cstring>
|
||||
- </property>
|
||||
- </widget>
|
||||
- </item>
|
||||
- <item row="0" column="1">
|
||||
- <widget class="QDoubleSpinBox" name="kcfg_ZoomFactor">
|
||||
- <property name="whatsThis">
|
||||
- <string>On zoom-in and zoom-out change the zoom by the defined zoom-factor.</string>
|
||||
- </property>
|
||||
- <property name="suffix">
|
||||
- <string/>
|
||||
- </property>
|
||||
- <property name="decimals">
|
||||
- <number>2</number>
|
||||
- </property>
|
||||
- <property name="maximum">
|
||||
- <double>9999.000000000000000</double>
|
||||
- </property>
|
||||
- <property name="singleStep">
|
||||
- <double>0.050000000000000</double>
|
||||
- </property>
|
||||
- <property name="value">
|
||||
- <double>1.250000000000000</double>
|
||||
- </property>
|
||||
- </widget>
|
||||
- </item>
|
||||
- <item row="4" column="0" colspan="2">
|
||||
- <widget class="QCheckBox" name="kcfg_EnableFocusTracking">
|
||||
- <property name="toolTip">
|
||||
- <string/>
|
||||
- </property>
|
||||
- <property name="whatsThis">
|
||||
- <string>Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1").</string>
|
||||
- </property>
|
||||
- <property name="text">
|
||||
- <string>Enable Focus Tracking</string>
|
||||
- </property>
|
||||
- </widget>
|
||||
- </item>
|
||||
- <item row="5" column="0" colspan="2">
|
||||
- <widget class="QCheckBox" name="kcfg_EnableTextCaretTracking">
|
||||
- <property name="whatsThis">
|
||||
- <string>Enable tracking of the text cursor. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1").</string>
|
||||
- </property>
|
||||
- <property name="text">
|
||||
- <string>Enable Text Cursor Tracking</string>
|
||||
- </property>
|
||||
- </widget>
|
||||
- </item>
|
||||
- <item row="2" column="0">
|
||||
- <widget class="QLabel" name="label_2">
|
||||
- <property name="text">
|
||||
- <string>Mouse Pointer:</string>
|
||||
- </property>
|
||||
- <property name="alignment">
|
||||
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
- </property>
|
||||
- <property name="buddy">
|
||||
- <cstring>kcfg_MousePointer</cstring>
|
||||
- </property>
|
||||
- </widget>
|
||||
- </item>
|
||||
- <item row="2" column="1">
|
||||
- <widget class="QComboBox" name="kcfg_MousePointer">
|
||||
- <property name="whatsThis">
|
||||
- <string>Visibility of the mouse-pointer.</string>
|
||||
- </property>
|
||||
- <item>
|
||||
- <property name="text">
|
||||
- <string>Scale</string>
|
||||
- </property>
|
||||
- </item>
|
||||
- <item>
|
||||
- <property name="text">
|
||||
- <string>Keep</string>
|
||||
- </property>
|
||||
- </item>
|
||||
- <item>
|
||||
- <property name="text">
|
||||
- <string>Hide</string>
|
||||
- </property>
|
||||
- </item>
|
||||
- </widget>
|
||||
- </item>
|
||||
- <item row="3" column="1">
|
||||
- <widget class="QComboBox" name="kcfg_MouseTracking">
|
||||
- <property name="whatsThis">
|
||||
- <string>Track moving of the mouse.</string>
|
||||
- </property>
|
||||
- <item>
|
||||
- <property name="text">
|
||||
- <string>Proportional</string>
|
||||
- </property>
|
||||
- </item>
|
||||
- <item>
|
||||
- <property name="text">
|
||||
- <string>Centered</string>
|
||||
- </property>
|
||||
- </item>
|
||||
- <item>
|
||||
- <property name="text">
|
||||
- <string>Push</string>
|
||||
- </property>
|
||||
- </item>
|
||||
- <item>
|
||||
- <property name="text">
|
||||
- <string>Disabled</string>
|
||||
- </property>
|
||||
- </item>
|
||||
- </widget>
|
||||
- </item>
|
||||
- <item row="3" column="0">
|
||||
- <widget class="QLabel" name="label_3">
|
||||
- <property name="text">
|
||||
- <string>Mouse Tracking:</string>
|
||||
- </property>
|
||||
- <property name="alignment">
|
||||
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
- </property>
|
||||
- <property name="buddy">
|
||||
- <cstring>kcfg_MouseTracking</cstring>
|
||||
- </property>
|
||||
- </widget>
|
||||
- </item>
|
||||
- </layout>
|
||||
- </item>
|
||||
- </layout>
|
||||
- </widget>
|
||||
+ <item row="0" column="0">
|
||||
+ <widget class="QLabel" name="label">
|
||||
+ <property name="whatsThis">
|
||||
+ <string>On zoom-in and zoom-out change the zoom by the defined zoom-factor.</string>
|
||||
+ </property>
|
||||
+ <property name="text">
|
||||
+ <string>Zoom factor:</string>
|
||||
+ </property>
|
||||
+ <property name="buddy">
|
||||
+ <cstring>kcfg_ZoomFactor</cstring>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="0" column="1">
|
||||
+ <widget class="QDoubleSpinBox" name="kcfg_ZoomFactor">
|
||||
+ <property name="whatsThis">
|
||||
+ <string>On zoom-in and zoom-out change the zoom by the defined zoom-factor.</string>
|
||||
+ </property>
|
||||
+ <property name="suffix">
|
||||
+ <string/>
|
||||
+ </property>
|
||||
+ <property name="decimals">
|
||||
+ <number>2</number>
|
||||
+ </property>
|
||||
+ <property name="maximum">
|
||||
+ <double>9999.000000000000000</double>
|
||||
+ </property>
|
||||
+ <property name="singleStep">
|
||||
+ <double>0.050000000000000</double>
|
||||
+ </property>
|
||||
+ <property name="value">
|
||||
+ <double>1.250000000000000</double>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="1" column="0">
|
||||
+ <widget class="QLabel" name="label_4">
|
||||
+ <property name="text">
|
||||
+ <string>Show pixel grid at zoom level:</string>
|
||||
+ </property>
|
||||
+ <property name="buddy">
|
||||
+ <cstring>kcfg_PixelGridZoom</cstring>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="1" column="1">
|
||||
+ <widget class="QDoubleSpinBox" name="kcfg_PixelGridZoom"/>
|
||||
+ </item>
|
||||
+ <item row="2" column="0">
|
||||
+ <widget class="QLabel" name="label_2">
|
||||
+ <property name="text">
|
||||
+ <string>Mouse pointer:</string>
|
||||
+ </property>
|
||||
+ <property name="buddy">
|
||||
+ <cstring>kcfg_MousePointer</cstring>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="2" column="1">
|
||||
+ <widget class="QComboBox" name="kcfg_MousePointer">
|
||||
+ <property name="whatsThis">
|
||||
+ <string>Visibility of the mouse-pointer.</string>
|
||||
+ </property>
|
||||
+ <item>
|
||||
+ <property name="text">
|
||||
+ <string>Scale</string>
|
||||
+ </property>
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <property name="text">
|
||||
+ <string>Keep</string>
|
||||
+ </property>
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <property name="text">
|
||||
+ <string>Hide</string>
|
||||
+ </property>
|
||||
+ </item>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="3" column="0">
|
||||
+ <widget class="QLabel" name="label_3">
|
||||
+ <property name="text">
|
||||
+ <string>Mouse tracking:</string>
|
||||
+ </property>
|
||||
+ <property name="buddy">
|
||||
+ <cstring>kcfg_MouseTracking</cstring>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="3" column="1">
|
||||
+ <widget class="QComboBox" name="kcfg_MouseTracking">
|
||||
+ <property name="whatsThis">
|
||||
+ <string>Track moving of the mouse.</string>
|
||||
+ </property>
|
||||
+ <item>
|
||||
+ <property name="text">
|
||||
+ <string>Proportional</string>
|
||||
+ </property>
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <property name="text">
|
||||
+ <string>Centered</string>
|
||||
+ </property>
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <property name="text">
|
||||
+ <string>Push</string>
|
||||
+ </property>
|
||||
+ </item>
|
||||
+ <item>
|
||||
+ <property name="text">
|
||||
+ <string>Disabled</string>
|
||||
+ </property>
|
||||
+ </item>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="4" column="1">
|
||||
+ <widget class="QCheckBox" name="kcfg_EnableFocusTracking">
|
||||
+ <property name="toolTip">
|
||||
+ <string/>
|
||||
+ </property>
|
||||
+ <property name="whatsThis">
|
||||
+ <string>Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1").</string>
|
||||
+ </property>
|
||||
+ <property name="text">
|
||||
+ <string>Enable focus tracking</string>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ <item row="5" column="1">
|
||||
+ <widget class="QCheckBox" name="kcfg_EnableTextCaretTracking">
|
||||
+ <property name="whatsThis">
|
||||
+ <string>Enable tracking of the text cursor. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1").</string>
|
||||
+ </property>
|
||||
+ <property name="text">
|
||||
+ <string>Enable text cursor tracking</string>
|
||||
+ </property>
|
||||
+ </widget>
|
||||
+ </item>
|
||||
+ </layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KShortcutsEditor" name="editor">
|
||||
@@ -183,13 +181,6 @@
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
- <tabstops>
|
||||
- <tabstop>kcfg_ZoomFactor</tabstop>
|
||||
- <tabstop>kcfg_MousePointer</tabstop>
|
||||
- <tabstop>kcfg_MouseTracking</tabstop>
|
||||
- <tabstop>kcfg_EnableFocusTracking</tabstop>
|
||||
- <tabstop>kcfg_EnableTextCaretTracking</tabstop>
|
||||
- </tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
From 45a5d8844b36404334301f5da6e75f1a345e0c80 Mon Sep 17 00:00:00 2001
|
||||
From: Xaver Hugl <xaver.hugl@gmail.com>
|
||||
Date: Fri, 10 Jan 2025 13:45:30 +0000
|
||||
Subject: [PATCH] plugins/screencast: call ItemRenderer::begin/endFrame
|
||||
|
||||
The OpenGL renderer references the explicit sync release points for client buffers
|
||||
during rendering, and releases them in endFrame. If endFrame never gets called though
|
||||
(for example because we're doing direct scanout) then the release points never get
|
||||
signaled, and the client very quickly runs out of buffers to use and freezes.
|
||||
|
||||
BUG: 495287
|
||||
|
||||
|
||||
(cherry picked from commit b1031ea63eaa8c9bf5c70157d1b6bf8eb0f5a74a)
|
||||
|
||||
Co-authored-by: Xaver Hugl <xaver.hugl@gmail.com>
|
||||
---
|
||||
src/plugins/screencast/windowscreencastsource.cpp | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/plugins/screencast/windowscreencastsource.cpp b/src/plugins/screencast/windowscreencastsource.cpp
|
||||
index 24ef92aad7b..b396eed46f9 100644
|
||||
--- a/src/plugins/screencast/windowscreencastsource.cpp
|
||||
+++ b/src/plugins/screencast/windowscreencastsource.cpp
|
||||
@@ -75,11 +75,11 @@ void WindowScreenCastSource::render(GLFramebuffer *target)
|
||||
RenderTarget renderTarget(target);
|
||||
RenderViewport viewport(m_window->clientGeometry(), 1, renderTarget);
|
||||
|
||||
- GLFramebuffer::pushFramebuffer(target);
|
||||
+ Compositor::self()->scene()->renderer()->beginFrame(renderTarget, viewport);
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
Compositor::self()->scene()->renderer()->renderItem(renderTarget, viewport, m_window->windowItem(), Scene::PAINT_WINDOW_TRANSFORMED, infiniteRegion(), WindowPaintData{});
|
||||
- GLFramebuffer::popFramebuffer();
|
||||
+ Compositor::self()->scene()->renderer()->endFrame();
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds WindowScreenCastSource::clock() const
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
From 626a52ae30dcda0ca407d1de02e30fcf5c109862 Mon Sep 17 00:00:00 2001
|
||||
From: Tem PQD <variable_valuables761@simplelogin.com>
|
||||
Date: Sun, 27 Oct 2024 03:54:44 +0000
|
||||
Subject: [PATCH] applets/taskmanager: Make group indicator icon follow accent
|
||||
color
|
||||
|
||||
The green plus icon is pretty eye-catching, and normally green plus buttons indicate something is going to be added or created. Change this to follow the user-selected color scheme, also matching the focus/active indicator color.
|
||||
---
|
||||
src/desktoptheme/breeze/widgets/tasks.svg | Bin 78569 -> 78717 bytes
|
||||
1 file changed, 0 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/src/desktoptheme/breeze/widgets/tasks.svg b/src/desktoptheme/breeze/widgets/tasks.svg
|
||||
index b76d1a345fe59ca48cc3c52de53495202734d00f..c60707355f082749661ffc059744a0f2b0f94eee 100644
|
||||
--- a/src/desktoptheme/breeze/widgets/tasks.svg
|
||||
+++ b/src/desktoptheme/breeze/widgets/tasks.svg
|
||||
@@ -952,25 +952,25 @@
|
||||
</g>
|
||||
<g id="group-expander-bottom" transform="matrix(1.2222222 0 0 1.2222222 -97 -16.777778)">
|
||||
<path id="path4927" d="m211.5 89.000002a4.4999957 4.5000003 0 0 0-4.5 4.5 4.4999957 4.5000003 0 0 0 4.5 4.5 4.4999957 4.5000003 0 0 0 4.5-4.5 4.4999957 4.5000003 0 0 0-4.5-4.5z" opacity=".25"/>
|
||||
- <path id="path4931" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="#2ecc71"/>
|
||||
+ <path id="path4931" class="ColorScheme-ButtonFocus" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="currentColor"/>
|
||||
<path id="path4930" d="m210.67561 91.045464.00097 1.630631-1.63462.01145.007 1.626089 1.63908.0091-.006 1.634313 1.62575-.005.007-1.631618 1.63976-.000027v-1.632877h-1.64636l.0204-1.642077z" opacity=".25"/>
|
||||
<path id="path4949" d="m211.08482 91.454555.00097 1.630633-1.63474.01145.007.807899 1.6392.0091-.006 1.634319.8077-.005.007-1.631624 1.63951-.000027v-.814687h-1.64611l.0204-1.642079z" fill="#fff"/>
|
||||
</g>
|
||||
<g id="group-expander-left" transform="matrix(1.2222222 0 0 1.2222222 -74.999995 -16.777778)">
|
||||
<path id="path4934" d="m211.5 89.000002a4.4999957 4.5000003 0 0 0-4.5 4.5 4.4999957 4.5000003 0 0 0 4.5 4.5 4.4999957 4.5000003 0 0 0 4.5-4.5 4.4999957 4.5000003 0 0 0-4.5-4.5z" opacity=".25"/>
|
||||
- <path id="path4938" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="#2ecc71"/>
|
||||
+ <path id="path4938" class="ColorScheme-ButtonFocus" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="currentColor"/>
|
||||
<path id="path4940" d="m210.67561 91.045464.00097 1.630631-1.63462.01145.007 1.626089 1.63908.0091-.006 1.634313 1.62575-.005.007-1.631618 1.63976-.000027v-1.632877h-1.64636l.0204-1.642077z" opacity=".25"/>
|
||||
<path id="path4942" d="m211.08482 91.454555.00097 1.630633-1.63474.01145.007.807899 1.6392.0091-.006 1.634319.8077-.005.007-1.631624 1.63951-.000027v-.814687h-1.64611l.0204-1.642079z" fill="#fff"/>
|
||||
</g>
|
||||
<g id="group-expander-top" transform="matrix(1.2222222 0 0 1.2222222 -97 1.222222)">
|
||||
<path id="path4946" d="m211.5 89.000002a4.4999957 4.5000003 0 0 0-4.5 4.5 4.4999957 4.5000003 0 0 0 4.5 4.5 4.4999957 4.5000003 0 0 0 4.5-4.5 4.4999957 4.5000003 0 0 0-4.5-4.5z" opacity=".25"/>
|
||||
- <path id="path4950" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="#2ecc71"/>
|
||||
+ <path id="path4950" class="ColorScheme-ButtonFocus" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="currentColor"/>
|
||||
<path id="path4952" d="m210.67561 91.045464.00097 1.630631-1.63462.01145.007 1.626089 1.63908.0091-.006 1.634313 1.62575-.005.007-1.631618 1.63976-.000027v-1.632877h-1.64636l.0204-1.642077z" opacity=".25"/>
|
||||
<path id="path4954" d="m211.08482 91.454555.00097 1.630633-1.63474.01145.007.807899 1.6392.0091-.006 1.634319.8077-.005.007-1.631624 1.63951-.000027v-.814687h-1.64611l.0204-1.642079z" fill="#fff"/>
|
||||
</g>
|
||||
<g id="group-expander-right" transform="matrix(1.2222222 0 0 1.2222222 -74.999995 1.222222)">
|
||||
<path id="path4958" d="m211.5 89.000002a4.4999957 4.5000003 0 0 0-4.5 4.5 4.4999957 4.5000003 0 0 0 4.5 4.5 4.4999957 4.5000003 0 0 0 4.5-4.5 4.4999957 4.5000003 0 0 0-4.5-4.5z" opacity=".25"/>
|
||||
- <path id="path4962" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="#2ecc71"/>
|
||||
+ <path id="path4962" class="ColorScheme-ButtonFocus" d="m211.50001 89.818184a3.6818164 3.6818182 0 0 0-3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182 3.681818 3.6818164 3.6818182 0 0 0 3.68182-3.681818 3.6818164 3.6818182 0 0 0-3.68182-3.681818z" fill="currentColor"/>
|
||||
<path id="path4964" d="m210.67561 91.045464.00097 1.630631-1.63462.01145.007 1.626089 1.63908.0091-.006 1.634313 1.62575-.005.007-1.631618 1.63976-.000027v-1.632877h-1.64636l.0204-1.642077z" opacity=".25"/>
|
||||
<path id="path4966" d="m211.08482 91.454555.00097 1.630633-1.63474.01145.007.807899 1.6392.0091-.006 1.634319.8077-.005.007-1.631624 1.63951-.000027v-.814687h-1.64611l.0204-1.642079z" fill="#fff"/>
|
||||
</g>
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
From 5301b211fc87f1b2253e87da61ff82618be9e899 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Niccol=C3=B2=20Venerandi?= <niccolo@venerandi.com>
|
||||
Date: Thu, 5 Dec 2024 16:12:58 +0100
|
||||
Subject: [PATCH] Only return valid task item size if task manager has been
|
||||
resized to fit panel
|
||||
|
||||
Previously the task manager would briefly have null width and height, before
|
||||
being resized to fit the panel. However, the "preferredMaxWidth" for tasks
|
||||
would still be positive, as it adds margins to it, and tasks would then
|
||||
assume a positive width. When the proper values are set, this casuses
|
||||
an extra resize animation.
|
||||
|
||||
CCBUG:447476
|
||||
---
|
||||
.../taskmanager/package/contents/ui/code/layoutmetrics.js | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/applets/taskmanager/package/contents/ui/code/layoutmetrics.js b/applets/taskmanager/package/contents/ui/code/layoutmetrics.js
|
||||
index c7f11c99a6..895cc725d2 100644
|
||||
--- a/applets/taskmanager/package/contents/ui/code/layoutmetrics.js
|
||||
+++ b/applets/taskmanager/package/contents/ui/code/layoutmetrics.js
|
||||
@@ -63,8 +63,14 @@ function preferredMinWidth() {
|
||||
function preferredMaxWidth() {
|
||||
if (tasks.iconsOnly) {
|
||||
if (tasks.vertical) {
|
||||
+ if (tasks.width === 0) {
|
||||
+ return 0
|
||||
+ }
|
||||
return tasks.width + verticalMargins();
|
||||
} else {
|
||||
+ if (tasks.height === 0) {
|
||||
+ return 0
|
||||
+ }
|
||||
return tasks.height + horizontalMargins();
|
||||
}
|
||||
}
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
From 11e7f5306fa013ec5c2b894a28457dabf5c42bad Mon Sep 17 00:00:00 2001
|
||||
From: Nate Graham <nate@kde.org>
|
||||
Date: Wed, 30 Oct 2024 21:55:49 -0600
|
||||
Subject: [PATCH] Merge "Settings" menu category into "System"
|
||||
|
||||
This category is a bit of an odd duck. On a default install, it contains
|
||||
only one item: System Settings. Random other apps you install will also
|
||||
appear there, but all of these could just as logically live in the
|
||||
"System" category. Let's put them there, so as to consolidate two
|
||||
nebulous overlapping categories into one clear and obvious one.
|
||||
---
|
||||
menu/desktop/plasma-applications.menu | 8 +-------
|
||||
1 file changed, 1 insertion(+), 7 deletions(-)
|
||||
|
||||
diff --git a/menu/desktop/plasma-applications.menu b/menu/desktop/plasma-applications.menu
|
||||
index e153604252e..85f842d6a04 100644
|
||||
--- a/menu/desktop/plasma-applications.menu
|
||||
+++ b/menu/desktop/plasma-applications.menu
|
||||
@@ -334,17 +334,11 @@
|
||||
</Include>
|
||||
</Menu>
|
||||
</Menu>
|
||||
- <Menu>
|
||||
- <Name>Settingsmenu</Name>
|
||||
- <Directory>kf5-settingsmenu.directory</Directory>
|
||||
- <Include>
|
||||
- <Category>Settings</Category>
|
||||
- </Include>
|
||||
- </Menu>
|
||||
<Menu>
|
||||
<Name>System</Name>
|
||||
<Directory>kf5-system.directory</Directory>
|
||||
<Include>
|
||||
+ <Category>Settings</Category>
|
||||
<And>
|
||||
<Category>System</Category>
|
||||
<Not><Category>X-KDE-More</Category></Not>
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
|
@ -1,915 +0,0 @@
|
|||
diff --git a/appiumtests/applets/CMakeLists.txt b/appiumtests/applets/CMakeLists.txt
|
||||
index 19229541aa..6715dd1f8f 100644
|
||||
--- a/appiumtests/applets/CMakeLists.txt
|
||||
+++ b/appiumtests/applets/CMakeLists.txt
|
||||
@@ -59,7 +59,7 @@ add_test(
|
||||
NAME notificationstest
|
||||
COMMAND selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/notificationstest.py --failfast
|
||||
)
|
||||
-set_tests_properties(notificationstest PROPERTIES TIMEOUT 120)
|
||||
+set_tests_properties(notificationstest PROPERTIES TIMEOUT 120 ENVIRONMENT "KACTIVITYMANAGERD_PATH=${KDE_INSTALL_FULL_LIBEXECDIR}/kactivitymanagerd;USE_CUSTOM_BUS=1")
|
||||
|
||||
add_test(
|
||||
NAME digitalclocktest
|
||||
diff --git a/appiumtests/applets/kicker/favoritetest.py b/appiumtests/applets/kicker/favoritetest.py
|
||||
new file mode 100755
|
||||
index 0000000000..50613c3db1
|
||||
--- /dev/null
|
||||
+++ b/appiumtests/applets/kicker/favoritetest.py
|
||||
@@ -0,0 +1,162 @@
|
||||
+#!/usr/bin/env python3
|
||||
+
|
||||
+# SPDX-License-Identifier: BSD-3-Clause
|
||||
+# SPDX-FileCopyrightText: 2022-2023 Harald Sitter <sitter@kde.org>
|
||||
+
|
||||
+import logging
|
||||
+import os
|
||||
+import shutil
|
||||
+import subprocess
|
||||
+import sys
|
||||
+import tempfile
|
||||
+import time
|
||||
+import unittest
|
||||
+from typing import Final
|
||||
+
|
||||
+from gi.repository import Gio, GLib
|
||||
+
|
||||
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir, "utils"))
|
||||
+from GLibMainLoopThread import GLibMainLoopThread
|
||||
+
|
||||
+KDE_VERSION: Final = 6
|
||||
+KACTIVITYMANAGERD_SERVICE_NAME: Final = "org.kde.ActivityManager"
|
||||
+KACTIVITYMANAGERD_PATH: Final = os.getenv("KACTIVITYMANAGERD_PATH", "/usr/libexec/kactivitymanagerd")
|
||||
+QMLTEST_EXEC: Final = os.getenv("QMLTEST_EXEC", "/usr/bin/qmltestrunner6")
|
||||
+
|
||||
+
|
||||
+def name_has_owner(session_bus: Gio.DBusConnection, name: str) -> bool:
|
||||
+ """
|
||||
+ Whether the given name is available on session bus
|
||||
+ """
|
||||
+ message: Gio.DBusMessage = Gio.DBusMessage.new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "NameHasOwner")
|
||||
+ message.set_body(GLib.Variant("(s)", [name]))
|
||||
+ reply, _ = session_bus.send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE, 1000)
|
||||
+ return reply and reply.get_signature() == 'b' and reply.get_body().get_child_value(0).get_boolean()
|
||||
+
|
||||
+
|
||||
+def build_ksycoca() -> None:
|
||||
+ subprocess.check_call([f"kbuildsycoca{KDE_VERSION}"], stdout=sys.stderr, stderr=sys.stderr, env=os.environ)
|
||||
+
|
||||
+
|
||||
+def start_kactivitymanagerd() -> subprocess.Popen:
|
||||
+ session_bus: Gio.DBusConnection = Gio.bus_get_sync(Gio.BusType.SESSION)
|
||||
+ assert not name_has_owner(session_bus, KACTIVITYMANAGERD_SERVICE_NAME)
|
||||
+
|
||||
+ os.makedirs(os.path.join(GLib.get_user_config_dir(), "menus"))
|
||||
+ shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), "applications.menu"), os.path.join(GLib.get_user_config_dir(), "menus"))
|
||||
+
|
||||
+ kactivitymanagerd = subprocess.Popen([KACTIVITYMANAGERD_PATH], stdout=sys.stderr, stderr=sys.stderr, env=os.environ)
|
||||
+ kactivitymanagerd_started: bool = False
|
||||
+ for _ in range(10):
|
||||
+ if name_has_owner(session_bus, KACTIVITYMANAGERD_SERVICE_NAME):
|
||||
+ kactivitymanagerd_started = True
|
||||
+ break
|
||||
+ logging.info("waiting for kactivitymanagerd to appear on the DBus session")
|
||||
+ time.sleep(1)
|
||||
+ assert kactivitymanagerd_started
|
||||
+
|
||||
+ build_ksycoca()
|
||||
+
|
||||
+ return kactivitymanagerd
|
||||
+
|
||||
+
|
||||
+class TestDBusInterface:
|
||||
+ """
|
||||
+ D-Bus interface for org.kde.kickertest
|
||||
+ """
|
||||
+
|
||||
+ BUS_NAME: Final = "org.kde.kickertest"
|
||||
+ OBJECT_PATH: Final = "/test"
|
||||
+ INTERFACE_NAME: Final = "org.kde.kickertest"
|
||||
+
|
||||
+ connection: Gio.DBusConnection
|
||||
+
|
||||
+ def __init__(self) -> None:
|
||||
+ self.reg_id: int = 0
|
||||
+ self.owner_id: int = Gio.bus_own_name(Gio.BusType.SESSION, self.BUS_NAME, Gio.BusNameOwnerFlags.NONE, self.on_bus_acquired, None, None)
|
||||
+ assert self.owner_id > 0
|
||||
+
|
||||
+ def on_bus_acquired(self, connection: Gio.DBusConnection, name: str, *args) -> None:
|
||||
+ """
|
||||
+ The interface is ready, now register objects.
|
||||
+ """
|
||||
+ self.connection = connection
|
||||
+ introspection_data = Gio.DBusNodeInfo.new_for_xml("""
|
||||
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
+<node>
|
||||
+ <interface name="org.kde.kickertest">
|
||||
+ <method name="DeleteAndRebuildDatabase1"/>
|
||||
+ <method name="DeleteAndRebuildDatabase2"/>
|
||||
+ </interface>
|
||||
+</node>
|
||||
+""")
|
||||
+ self.reg_id = connection.register_object(self.OBJECT_PATH, introspection_data.interfaces[0], self.handle_method_call, None, None)
|
||||
+ assert self.reg_id > 0
|
||||
+ logging.info("interface registered")
|
||||
+
|
||||
+ def handle_method_call(self, connection: Gio.DBusConnection, sender: str, object_path: str, interface_name: str, method_name: str, parameters: GLib.Variant, invocation: Gio.DBusMethodInvocation) -> None:
|
||||
+ logging.info("method call %s", method_name)
|
||||
+
|
||||
+ if method_name == "DeleteAndRebuildDatabase1":
|
||||
+ os.remove(KickerTest.desktop_entry_1)
|
||||
+ build_ksycoca()
|
||||
+ invocation.return_value(None)
|
||||
+ elif method_name == "DeleteAndRebuildDatabase2":
|
||||
+ os.remove(KickerTest.desktop_entry_2)
|
||||
+ build_ksycoca()
|
||||
+ invocation.return_value(None)
|
||||
+
|
||||
+
|
||||
+class KickerTest(unittest.TestCase):
|
||||
+ kactivitymanagerd: subprocess.Popen
|
||||
+ loop_thread: GLibMainLoopThread
|
||||
+ dbus_interface: TestDBusInterface
|
||||
+
|
||||
+ temp_dir: tempfile.TemporaryDirectory
|
||||
+ desktop_entry_1: str
|
||||
+ desktop_entry_2: str
|
||||
+
|
||||
+ @classmethod
|
||||
+ def setUpClass(cls) -> None:
|
||||
+ # Prepare desktop files
|
||||
+ # 1
|
||||
+ os.makedirs(os.path.join(GLib.get_user_data_dir(), "applications"))
|
||||
+ shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), "kickertest.desktop"), os.path.join(GLib.get_user_data_dir(), "applications"))
|
||||
+ cls.desktop_entry_1 = os.path.join(GLib.get_user_data_dir(), "applications", "kickertest.desktop")
|
||||
+ # 2
|
||||
+ cls.temp_dir = tempfile.TemporaryDirectory()
|
||||
+ os.makedirs(os.path.join(cls.temp_dir.name, "applications"))
|
||||
+ shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), "kickertest.desktop"), os.path.join(cls.temp_dir.name, "applications"))
|
||||
+ cls.desktop_entry_2 = os.path.join(cls.temp_dir.name, "applications", "kickertest.desktop")
|
||||
+
|
||||
+ os.environ["LC_ALL"] = "en_US.UTF-8"
|
||||
+ os.environ["QT_LOGGING_RULES"] = "org.kde.plasma.kicker.debug=true;kf.coreaddons.kdirwatch.debug=true"
|
||||
+ os.environ["XDG_DATA_DIRS"] = os.environ["XDG_DATA_DIRS"] + ":" + cls.temp_dir.name
|
||||
+
|
||||
+ cls.kactivitymanagerd = start_kactivitymanagerd()
|
||||
+
|
||||
+ cls.loop_thread = GLibMainLoopThread()
|
||||
+ cls.loop_thread.start()
|
||||
+ cls.dbus_interface = TestDBusInterface()
|
||||
+
|
||||
+ @classmethod
|
||||
+ def tearDownClass(cls) -> None:
|
||||
+ cls.loop_thread.quit()
|
||||
+ cls.kactivitymanagerd.kill()
|
||||
+ cls.kactivitymanagerd.wait(10)
|
||||
+
|
||||
+ def test_qml(self) -> None:
|
||||
+ """
|
||||
+ 1. Add an entry to Favorites
|
||||
+ 2. Remove the entry from Favorites
|
||||
+ 3. Hide invalid entries automatically and don't crash when there are multiple entries with the same desktop name
|
||||
+ """
|
||||
+ with subprocess.Popen([QMLTEST_EXEC, "-input", os.path.join(os.path.dirname(os.path.abspath(__file__)), 'favoritetest.qml')], stdout=sys.stderr, stderr=sys.stderr) as process:
|
||||
+ self.assertEqual(process.wait(60), 0)
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ assert "USE_CUSTOM_BUS" in os.environ
|
||||
+ logging.getLogger().setLevel(logging.INFO)
|
||||
+ unittest.main()
|
||||
diff --git a/appiumtests/applets/notificationstest.py b/appiumtests/applets/notificationstest.py
|
||||
index 8917121a94..cd34a32905 100755
|
||||
--- a/appiumtests/applets/notificationstest.py
|
||||
+++ b/appiumtests/applets/notificationstest.py
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import base64
|
||||
import os
|
||||
+import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
@@ -15,6 +16,7 @@ import gi
|
||||
from appium import webdriver
|
||||
from appium.options.common.base import AppiumOptions
|
||||
from appium.webdriver.common.appiumby import AppiumBy
|
||||
+from selenium.common.exceptions import (NoSuchElementException, WebDriverException)
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
@@ -22,6 +24,8 @@ gi.require_version('Gdk', '4.0')
|
||||
gi.require_version('GdkPixbuf', '2.0')
|
||||
from gi.repository import Gdk, GdkPixbuf, Gio, GLib
|
||||
|
||||
+from kicker.favoritetest import start_kactivitymanagerd
|
||||
+
|
||||
WIDGET_ID: Final = "org.kde.plasma.notifications"
|
||||
KDE_VERSION: Final = 6
|
||||
|
||||
@@ -48,17 +52,25 @@ class NotificationsTest(unittest.TestCase):
|
||||
"""
|
||||
|
||||
driver: webdriver.Remote
|
||||
+ kactivitymanagerd: subprocess.Popen
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
"""
|
||||
Opens the widget and initialize the webdriver
|
||||
"""
|
||||
+ # Make history work
|
||||
+ cls.kactivitymanagerd = start_kactivitymanagerd()
|
||||
+
|
||||
+ os.makedirs(os.path.join(GLib.get_user_data_dir(), "knotifications6"))
|
||||
+ shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir, "libnotificationmanager", "libnotificationmanager.notifyrc"), os.path.join(GLib.get_user_data_dir(), "knotifications6"))
|
||||
+
|
||||
options = AppiumOptions()
|
||||
options.set_capability("app", f"plasmawindowed -p org.kde.plasma.nano {WIDGET_ID}")
|
||||
options.set_capability("timeouts", {'implicit': 10000})
|
||||
options.set_capability("environ", {
|
||||
"LC_ALL": "en_US.UTF-8",
|
||||
+ "QT_LOGGING_RULES": "kf.notification*.debug=true;org.kde.plasma.notificationmanager.debug=true",
|
||||
})
|
||||
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options)
|
||||
|
||||
@@ -75,6 +87,8 @@ class NotificationsTest(unittest.TestCase):
|
||||
Make sure to terminate the driver again, lest it dangles.
|
||||
"""
|
||||
subprocess.check_call([f"kquitapp{KDE_VERSION}", "plasmawindowed"])
|
||||
+ cls.kactivitymanagerd.kill()
|
||||
+ cls.kactivitymanagerd.wait(10)
|
||||
for _ in range(10):
|
||||
try:
|
||||
subprocess.check_call(["pidof", "plasmawindowed"])
|
||||
@@ -83,6 +97,15 @@ class NotificationsTest(unittest.TestCase):
|
||||
time.sleep(1)
|
||||
cls.driver.quit()
|
||||
|
||||
+ def close_notifications(self) -> None:
|
||||
+ wait = WebDriverWait(self.driver, 5)
|
||||
+ for button in self.driver.find_elements(AppiumBy.XPATH, "//button[@name='Close']"):
|
||||
+ try:
|
||||
+ button.click()
|
||||
+ wait.until_not(lambda _: button.is_displayed())
|
||||
+ except WebDriverException:
|
||||
+ pass
|
||||
+
|
||||
def test_0_open(self) -> None:
|
||||
"""
|
||||
Tests the widget can be opened
|
||||
@@ -106,6 +129,10 @@ class NotificationsTest(unittest.TestCase):
|
||||
|
||||
wait = WebDriverWait(self.driver, 5)
|
||||
wait.until(EC.presence_of_element_located((AppiumBy.NAME, summary)))
|
||||
+<<<<<<< HEAD
|
||||
+=======
|
||||
+ self.close_notifications()
|
||||
+>>>>>>> 5145d877d8 (applets/notifications: suppress inhibited notifications after "Do not disturb" is off)
|
||||
|
||||
def take_screenshot(self) -> str:
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
@@ -123,6 +150,7 @@ class NotificationsTest(unittest.TestCase):
|
||||
partial_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 16, 16)
|
||||
colors = (0xff0000ff, 0x00ff00ff, 0x0000ffff)
|
||||
for color in colors:
|
||||
+ logging.info(f"Testing color: {color}")
|
||||
pixbuf.fill(color)
|
||||
send_notification({
|
||||
"app_name": "Appium Test",
|
||||
@@ -145,7 +173,29 @@ class NotificationsTest(unittest.TestCase):
|
||||
wait.until(EC.presence_of_element_located((AppiumBy.NAME, summary + str(color))))
|
||||
partial_pixbuf.fill(color)
|
||||
partial_image = base64.b64encode(Gdk.Texture.new_for_pixbuf(partial_pixbuf).save_to_png_bytes().get_data()).decode()
|
||||
+<<<<<<< HEAD
|
||||
self.driver.find_image_occurrence(self.take_screenshot(), partial_image)
|
||||
+=======
|
||||
+ try:
|
||||
+ self.driver.find_image_occurrence(self.take_screenshot(), partial_image)
|
||||
+ except WebDriverException: # Popup animation
|
||||
+ self.driver.find_image_occurrence(self.take_screenshot(), partial_image)
|
||||
+ self.close_notifications()
|
||||
+
|
||||
+ def test_2_notification_with_explicit_timeout(self) -> None:
|
||||
+ """
|
||||
+ Sends notifications with expire_timeout
|
||||
+ """
|
||||
+ summary = "expire_timeout"
|
||||
+ send_notification({
|
||||
+ "app_name": "Appium Test",
|
||||
+ "summary": summary,
|
||||
+ "body": "Will it disappear automatically?",
|
||||
+ "timeout": 2000,
|
||||
+ })
|
||||
+ element = self.driver.find_element(AppiumBy.NAME, summary)
|
||||
+ WebDriverWait(self.driver, 5).until_not(lambda _: element.is_displayed())
|
||||
+>>>>>>> 5145d877d8 (applets/notifications: suppress inhibited notifications after "Do not disturb" is off)
|
||||
|
||||
def test_3_accessible_description_html_to_plaintext(self) -> None:
|
||||
"""
|
||||
@@ -157,6 +207,202 @@ class NotificationsTest(unittest.TestCase):
|
||||
})
|
||||
wait = WebDriverWait(self.driver, 5)
|
||||
wait.until(EC.presence_of_element_located(("description", "biublinkwww.example.org from Appium Test")))
|
||||
+<<<<<<< HEAD
|
||||
+=======
|
||||
+ self.close_notifications()
|
||||
+
|
||||
+ def test_4_actions(self) -> None:
|
||||
+ """
|
||||
+ When the "actions" key is set, a notification can provide actions.
|
||||
+ """
|
||||
+ loop = GLib.MainLoop()
|
||||
+ activation_token = False
|
||||
+ params_1: list[Any] = []
|
||||
+ action_invoked = False
|
||||
+ params_2: list[Any] = []
|
||||
+ notification_closed = False
|
||||
+ params_3: list[Any] = []
|
||||
+
|
||||
+ def notification_signal_handler(d_bus_proxy: Gio.DBusProxy, sender_name: str, signal_name: str, parameters: GLib.Variant) -> None:
|
||||
+ nonlocal params_2, params_3, params_1, activation_token, action_invoked, notification_closed
|
||||
+ logging.info(f"received signal {signal_name}")
|
||||
+ match signal_name:
|
||||
+ case "ActivationToken":
|
||||
+ params_1 = parameters.unpack()
|
||||
+ activation_token = True
|
||||
+ case "ActionInvoked":
|
||||
+ params_2 = parameters.unpack()
|
||||
+ action_invoked = True
|
||||
+ case "NotificationClosed":
|
||||
+ params_3 = parameters.unpack()
|
||||
+ notification_closed = True
|
||||
+ loop.quit()
|
||||
+
|
||||
+ connection_id = self.notification_proxy.connect("g-signal", notification_signal_handler)
|
||||
+ self.addCleanup(lambda: self.notification_proxy.disconnect(connection_id))
|
||||
+
|
||||
+ notification_id = send_notification({
|
||||
+ "app_name": "Appium Test",
|
||||
+ "body": "A notification with actions",
|
||||
+ "actions": ["action1", "FooAction", "action2", "BarAction"],
|
||||
+ })
|
||||
+ self.driver.find_element(AppiumBy.NAME, "BarAction")
|
||||
+ element = self.driver.find_element(AppiumBy.NAME, "FooAction")
|
||||
+ element.click()
|
||||
+ loop.run()
|
||||
+ self.assertTrue(activation_token)
|
||||
+ self.assertEqual(params_1[0], notification_id)
|
||||
+ self.assertTrue(action_invoked)
|
||||
+ self.assertEqual(params_2[0], notification_id)
|
||||
+ self.assertEqual(params_2[1], "action1")
|
||||
+ self.assertTrue(notification_closed)
|
||||
+ self.assertEqual(params_3[0], notification_id)
|
||||
+ self.assertEqual(params_3[1], 3) # reason: Revoked
|
||||
+ self.assertFalse(element.is_displayed())
|
||||
+
|
||||
+ def test_5_inline_reply(self) -> None:
|
||||
+ """
|
||||
+ When the action list has "inline-reply", the notification popup will contain a text field and a reply button.
|
||||
+ """
|
||||
+ loop = GLib.MainLoop()
|
||||
+ notification_replied = False
|
||||
+ params: list[Any] = [] # id, text
|
||||
+
|
||||
+ def notification_signal_handler(d_bus_proxy: Gio.DBusProxy, sender_name: str, signal_name: str, parameters: GLib.Variant) -> None:
|
||||
+ nonlocal params, notification_replied
|
||||
+ logging.info(f"received signal {signal_name}")
|
||||
+ if signal_name == "NotificationReplied":
|
||||
+ params = parameters.unpack()
|
||||
+ notification_replied = True
|
||||
+ loop.quit()
|
||||
+
|
||||
+ connection_id = self.notification_proxy.connect("g-signal", notification_signal_handler)
|
||||
+ self.addCleanup(lambda: self.notification_proxy.disconnect(connection_id))
|
||||
+
|
||||
+ # When there is only one action and it is a reply action, show text field right away
|
||||
+ notification_id = send_notification({
|
||||
+ "app_name": "Appium Test",
|
||||
+ "body": "A notification with actions 1",
|
||||
+ "actions": ["inline-reply", ""], # Use the default label
|
||||
+ })
|
||||
+ reply_text = "this is a reply"
|
||||
+ self.driver.find_element(AppiumBy.NAME, "begin reply").click()
|
||||
+ self.driver.find_element(AppiumBy.NAME, "Type a reply…").send_keys(reply_text)
|
||||
+ element = self.driver.find_element(AppiumBy.NAME, "Send")
|
||||
+ element.click()
|
||||
+ loop.run()
|
||||
+ self.assertTrue(notification_replied)
|
||||
+ self.assertEqual(params[0], notification_id)
|
||||
+ self.assertEqual(params[1], reply_text)
|
||||
+ self.assertFalse(element.is_displayed())
|
||||
+
|
||||
+ notification_replied = False
|
||||
+ notification_id = send_notification({
|
||||
+ "app_name": "Appium Test",
|
||||
+ "body": "A notification with actions 2",
|
||||
+ "actions": ["inline-reply", ""],
|
||||
+ "hints": {
|
||||
+ "x-kde-reply-submit-button-text": GLib.Variant("s", "Reeply"), # Use a custom label
|
||||
+ "x-kde-reply-placeholder-text": GLib.Variant("s", "A placeholder"), # Use a custom placeholder
|
||||
+ },
|
||||
+ })
|
||||
+ reply_text = "this is another reply"
|
||||
+ self.driver.find_element(AppiumBy.NAME, "begin reply").click()
|
||||
+ self.driver.find_element(AppiumBy.NAME, "A placeholder").send_keys(reply_text)
|
||||
+ element = self.driver.find_element(AppiumBy.NAME, "Reeply")
|
||||
+ element.click()
|
||||
+ loop.run()
|
||||
+ self.assertTrue(notification_replied)
|
||||
+ self.assertEqual(params[0], notification_id)
|
||||
+ self.assertEqual(params[1], reply_text)
|
||||
+ self.assertFalse(element.is_displayed())
|
||||
+
|
||||
+ notification_replied = False
|
||||
+ notification_id = send_notification({
|
||||
+ "app_name": "Appium Test",
|
||||
+ "body": "A notification with actions 3",
|
||||
+ "actions": ["inline-reply", "Replyy", "foo", "Foo", "bar", "Bar"], # Click to show the text field
|
||||
+ })
|
||||
+ self.driver.find_element(AppiumBy.NAME, "Foo")
|
||||
+ self.driver.find_element(AppiumBy.NAME, "Bar")
|
||||
+ element = self.driver.find_element(AppiumBy.NAME, "Replyy")
|
||||
+ element.click()
|
||||
+ reply_text = "Click Replyy to reply"
|
||||
+ self.driver.find_element(AppiumBy.NAME, "Type a reply…").send_keys(reply_text)
|
||||
+ self.assertFalse(element.is_displayed())
|
||||
+ element = self.driver.find_element(AppiumBy.NAME, "Send")
|
||||
+ element.click()
|
||||
+ loop.run()
|
||||
+ self.assertTrue(notification_replied)
|
||||
+ self.assertEqual(params[0], notification_id)
|
||||
+ self.assertEqual(params[1], reply_text)
|
||||
+
|
||||
+ def test_6_thumbnail(self) -> None:
|
||||
+ """
|
||||
+ When a notification has "x-kde-urls" hint, a thumbnail will be shown for the first url in the list
|
||||
+ """
|
||||
+ with tempfile.TemporaryDirectory() as temp_dir:
|
||||
+ pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 256, 256)
|
||||
+ colors = (0xff0000ff, 0x00ff00ff, 0x0000ffff)
|
||||
+ for color in colors:
|
||||
+ pixbuf.fill(color)
|
||||
+ pixbuf.savev(os.path.join(temp_dir, f"{str(color)}.png"), "png")
|
||||
+
|
||||
+ url_list = [f"file://{os.path.join(temp_dir, path)}" for path in os.listdir(temp_dir)]
|
||||
+ url_list.sort()
|
||||
+ send_notification({
|
||||
+ "app_name": "Appium Test",
|
||||
+ "body": "Thumbnail",
|
||||
+ "hints": {
|
||||
+ "x-kde-urls": GLib.Variant("as", url_list),
|
||||
+ },
|
||||
+ "timeout": 10 * 1000,
|
||||
+ })
|
||||
+
|
||||
+ self.driver.find_element(AppiumBy.NAME, "More Options…")
|
||||
+
|
||||
+ partial_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 100, 100)
|
||||
+ partial_pixbuf.fill(colors[1]) # Green is the first item
|
||||
+ partial_image = base64.b64encode(Gdk.Texture.new_for_pixbuf(partial_pixbuf).save_to_png_bytes().get_data()).decode()
|
||||
+
|
||||
+ def match_image(driver) -> bool:
|
||||
+ try:
|
||||
+ self.driver.find_image_occurrence(self.take_screenshot(), partial_image)
|
||||
+ return True
|
||||
+ except WebDriverException:
|
||||
+ return False
|
||||
+
|
||||
+ WebDriverWait(self.driver, 10).until(match_image)
|
||||
+ self.close_notifications()
|
||||
+
|
||||
+ def test_7_do_not_disturb(self) -> None:
|
||||
+ """
|
||||
+ Suppress inhibited notifications after "Do not disturb" is turned off, and show a summary for unread inhibited notifications.
|
||||
+ """
|
||||
+ self.driver.find_element(AppiumBy.NAME, "Do not disturb").click()
|
||||
+ dnd_button = self.driver.find_element(AppiumBy.XPATH, "//*[@name='Do not disturb' and contains(@states, 'checked')]")
|
||||
+
|
||||
+ summary = "Do not disturb me"
|
||||
+ for i in range(2):
|
||||
+ send_notification({
|
||||
+ "app_name": "Appium Test",
|
||||
+ "summary": summary + str(i),
|
||||
+ "hints": {
|
||||
+ "desktop-entry": GLib.Variant("s", "org.kde.plasmashell"),
|
||||
+ },
|
||||
+ "timeout": 60 * 1000,
|
||||
+ })
|
||||
+ title = self.driver.find_element(AppiumBy.XPATH, f"//heading[starts-with(@name, '{summary}') and contains(@accessibility-id, 'FullRepresentation')]")
|
||||
+ self.assertRaises(NoSuchElementException, self.driver.find_element, AppiumBy.XPATH, f"//notification[starts-with(@name, '{summary}')]")
|
||||
+
|
||||
+ dnd_button.click()
|
||||
+ self.driver.find_element(AppiumBy.XPATH, "//notification[@name='Unread Notifications' and @description='2 notifications were received while Do Not Disturb was active. from Notification Manager']")
|
||||
+ self.driver.find_element(AppiumBy.XPATH, "//button[@name='Close' and contains(@accessibility-id, 'NotificationPopup')]").click()
|
||||
+
|
||||
+ # Notifications can only be cleared after they are expired, otherwise they will stay in the list
|
||||
+ self.driver.find_element(AppiumBy.NAME, "Clear All Notifications").click()
|
||||
+ WebDriverWait(self.driver, 5).until_not(lambda _: title.is_displayed())
|
||||
+>>>>>>> 5145d877d8 (applets/notifications: suppress inhibited notifications after "Do not disturb" is off)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
diff --git a/applets/notifications/package/contents/ui/FullRepresentation.qml b/applets/notifications/package/contents/ui/FullRepresentation.qml
|
||||
index f949dad46a..33838599f6 100644
|
||||
--- a/applets/notifications/package/contents/ui/FullRepresentation.qml
|
||||
+++ b/applets/notifications/package/contents/ui/FullRepresentation.qml
|
||||
@@ -71,6 +71,14 @@ PlasmaExtras.Representation {
|
||||
checkable: true
|
||||
checked: Globals.inhibited
|
||||
|
||||
+ Accessible.onPressAction: if (Globals.inhibited) {
|
||||
+ Globals.revokeInhibitions();
|
||||
+ } else {
|
||||
+ let date = new Date();
|
||||
+ date.setFullYear(date.getFullYear() + 1);
|
||||
+ notificationSettings.notificationsInhibitedUntil = date;
|
||||
+ notificationSettings.save();
|
||||
+ }
|
||||
KeyNavigation.down: list
|
||||
KeyNavigation.tab: list
|
||||
|
||||
diff --git a/applets/notifications/package/contents/ui/global/Globals.qml b/applets/notifications/package/contents/ui/global/Globals.qml
|
||||
index c46c32921a..2238653eff 100644
|
||||
--- a/applets/notifications/package/contents/ui/global/Globals.qml
|
||||
+++ b/applets/notifications/package/contents/ui/global/Globals.qml
|
||||
@@ -34,6 +34,10 @@ QtObject {
|
||||
property bool inhibited: false
|
||||
|
||||
onInhibitedChanged: {
|
||||
+ if (!inhibited) {
|
||||
+ popupNotificationsModel.showInhibitionSummary();
|
||||
+ }
|
||||
+
|
||||
var pa = pulseAudio.item;
|
||||
if (!pa) {
|
||||
return;
|
||||
@@ -405,6 +409,7 @@ QtObject {
|
||||
limit: plasmoid ? (Math.ceil(globals.screenRect.height / (Kirigami.Units.gridUnit * 4))) : 0
|
||||
showExpired: false
|
||||
showDismissed: false
|
||||
+ showAddedDuringInhibition: false
|
||||
blacklistedDesktopEntries: notificationSettings.popupBlacklistedApplications
|
||||
blacklistedNotifyRcNames: notificationSettings.popupBlacklistedServices
|
||||
whitelistedDesktopEntries: globals.inhibited ? notificationSettings.doNotDisturbPopupWhitelistedApplications : []
|
||||
@@ -613,9 +618,13 @@ QtObject {
|
||||
onKillJobClicked: popupNotificationsModel.killJob(popupNotificationsModel.index(index, 0))
|
||||
|
||||
// popup width is fixed
|
||||
- onHeightChanged: positionPopups()
|
||||
+ onHeightChanged: globals.positionPopups()
|
||||
|
||||
Component.onCompleted: {
|
||||
+ if (globals.inhibited) {
|
||||
+ model.wasAddedDuringInhibition = false; // Don't count already shown notifications
|
||||
+ }
|
||||
+
|
||||
if (model.type === NotificationManager.Notifications.NotificationType && model.desktopEntry) {
|
||||
// Register apps that were seen spawning a popup so they can be configured later
|
||||
// Apps with notifyrc can already be configured anyway
|
||||
diff --git a/libnotificationmanager/CMakeLists.txt b/libnotificationmanager/CMakeLists.txt
|
||||
index d04d8a4a24..5c48653ede 100644
|
||||
--- a/libnotificationmanager/CMakeLists.txt
|
||||
+++ b/libnotificationmanager/CMakeLists.txt
|
||||
@@ -84,6 +84,7 @@ target_link_libraries(notificationmanager
|
||||
KF6::I18n
|
||||
KF6::WindowSystem
|
||||
KF6::ItemModels # KDescendantsProxyModel
|
||||
+ KF6::Notifications # Inhibition summary
|
||||
KF6::KIOFileWidgets
|
||||
Plasma::Plasma
|
||||
KF6::Screen
|
||||
@@ -135,3 +136,6 @@ install(EXPORT notificationmanagerLibraryTargets
|
||||
|
||||
install(FILES plasmanotifyrc
|
||||
DESTINATION ${KDE_INSTALL_CONFDIR})
|
||||
+
|
||||
+install(FILES libnotificationmanager.notifyrc
|
||||
+ DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
||||
diff --git a/libnotificationmanager/abstractnotificationsmodel.cpp b/libnotificationmanager/abstractnotificationsmodel.cpp
|
||||
index 8bd55bc26c..8307a1e8f7 100644
|
||||
--- a/libnotificationmanager/abstractnotificationsmodel.cpp
|
||||
+++ b/libnotificationmanager/abstractnotificationsmodel.cpp
|
||||
@@ -104,6 +104,7 @@ void AbstractNotificationsModel::Private::onNotificationReplaced(uint replacedId
|
||||
newNotification.setExpired(oldNotification.expired());
|
||||
newNotification.setDismissed(oldNotification.dismissed());
|
||||
newNotification.setRead(oldNotification.read());
|
||||
+ newNotification.setWasAddedDuringInhibition(Server::self().inhibited());
|
||||
|
||||
notifications[row] = newNotification;
|
||||
const QModelIndex idx = q->index(row, 0);
|
||||
@@ -378,6 +379,9 @@ QVariant AbstractNotificationsModel::data(const QModelIndex &index, int role) co
|
||||
case Notifications::TransientRole:
|
||||
return notification.transient();
|
||||
|
||||
+ case Notifications::WasAddedDuringInhibitionRole:
|
||||
+ return notification.wasAddedDuringInhibition();
|
||||
+
|
||||
case Notifications::HasReplyActionRole:
|
||||
return notification.hasReplyAction();
|
||||
case Notifications::ReplyActionLabelRole:
|
||||
@@ -416,6 +420,12 @@ bool AbstractNotificationsModel::setData(const QModelIndex &index, const QVarian
|
||||
dirty = true;
|
||||
}
|
||||
break;
|
||||
+ case Notifications::WasAddedDuringInhibitionRole:
|
||||
+ if (bool v = value.toBool(); v != notification.wasAddedDuringInhibition()) {
|
||||
+ notification.setWasAddedDuringInhibition(v);
|
||||
+ dirty = true;
|
||||
+ }
|
||||
+ break;
|
||||
}
|
||||
|
||||
if (dirty) {
|
||||
@@ -471,7 +481,7 @@ void AbstractNotificationsModel::clear(Notifications::ClearFlags flags)
|
||||
for (int i = 0; i < d->notifications.count(); ++i) {
|
||||
const Notification ¬ification = d->notifications.at(i);
|
||||
|
||||
- if (flags.testFlag(Notifications::ClearExpired) && notification.expired()) {
|
||||
+ if (flags.testFlag(Notifications::ClearExpired) && (notification.expired() || notification.wasAddedDuringInhibition())) {
|
||||
close(notification.id());
|
||||
}
|
||||
}
|
||||
diff --git a/libnotificationmanager/libnotificationmanager.notifyrc b/libnotificationmanager/libnotificationmanager.notifyrc
|
||||
new file mode 100644
|
||||
index 0000000000..79304e62bc
|
||||
--- /dev/null
|
||||
+++ b/libnotificationmanager/libnotificationmanager.notifyrc
|
||||
@@ -0,0 +1,11 @@
|
||||
+# SPDX-License-Identifier: CC0-1.0
|
||||
+# SPDX-FileCopyrightText: None
|
||||
+
|
||||
+[Global]
|
||||
+Name=Notification Manager
|
||||
+IconName=preferences-desktop-notification-bell
|
||||
+
|
||||
+[Event/inhibitionSummary]
|
||||
+Name=Summary for unread inhibited notifications
|
||||
+Action=Popup
|
||||
+Urgency=Low
|
||||
diff --git a/libnotificationmanager/notification.cpp b/libnotificationmanager/notification.cpp
|
||||
index 276611310c..320c837617 100644
|
||||
--- a/libnotificationmanager/notification.cpp
|
||||
+++ b/libnotificationmanager/notification.cpp
|
||||
@@ -826,3 +826,13 @@ void Notification::processHints(const QVariantMap &hints)
|
||||
{
|
||||
d->processHints(hints);
|
||||
}
|
||||
+
|
||||
+bool Notification::wasAddedDuringInhibition() const
|
||||
+{
|
||||
+ return d->wasAddedDuringInhibition;
|
||||
+}
|
||||
+
|
||||
+void Notification::setWasAddedDuringInhibition(bool value)
|
||||
+{
|
||||
+ d->wasAddedDuringInhibition = value;
|
||||
+}
|
||||
diff --git a/libnotificationmanager/notification.h b/libnotificationmanager/notification.h
|
||||
index 9f04a4e200..8613534fd2 100644
|
||||
--- a/libnotificationmanager/notification.h
|
||||
+++ b/libnotificationmanager/notification.h
|
||||
@@ -131,6 +131,9 @@ public:
|
||||
|
||||
void processHints(const QVariantMap &hints);
|
||||
|
||||
+ bool wasAddedDuringInhibition() const;
|
||||
+ void setWasAddedDuringInhibition(bool value);
|
||||
+
|
||||
private:
|
||||
friend class NotificationsModel;
|
||||
friend class AbstractNotificationsModel;
|
||||
diff --git a/libnotificationmanager/notification_p.h b/libnotificationmanager/notification_p.h
|
||||
index 6cae23c21e..923bde7882 100644
|
||||
--- a/libnotificationmanager/notification_p.h
|
||||
+++ b/libnotificationmanager/notification_p.h
|
||||
@@ -96,6 +96,8 @@ public:
|
||||
|
||||
bool resident = false;
|
||||
bool transient = false;
|
||||
+
|
||||
+ bool wasAddedDuringInhibition = false;
|
||||
};
|
||||
|
||||
} // namespace NotificationManager
|
||||
diff --git a/libnotificationmanager/notificationfilterproxymodel.cpp b/libnotificationmanager/notificationfilterproxymodel.cpp
|
||||
index 98a32b6645..bb573713af 100644
|
||||
--- a/libnotificationmanager/notificationfilterproxymodel.cpp
|
||||
+++ b/libnotificationmanager/notificationfilterproxymodel.cpp
|
||||
@@ -58,6 +58,20 @@ void NotificationFilterProxyModel::setShowDismissed(bool show)
|
||||
}
|
||||
}
|
||||
|
||||
+bool NotificationFilterProxyModel::showAddedDuringInhibition() const
|
||||
+{
|
||||
+ return m_showDismissed;
|
||||
+}
|
||||
+
|
||||
+void NotificationFilterProxyModel::setShowAddedDuringInhibition(bool show)
|
||||
+{
|
||||
+ if (m_showAddedDuringInhibition != show) {
|
||||
+ m_showAddedDuringInhibition = show;
|
||||
+ invalidateFilter();
|
||||
+ Q_EMIT showAddedDuringInhibitionChanged();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
QStringList NotificationFilterProxyModel::blacklistedDesktopEntries() const
|
||||
{
|
||||
return m_blacklistedDesktopEntries;
|
||||
@@ -177,5 +191,9 @@ bool NotificationFilterProxyModel::filterAcceptsRow(int source_row, const QModel
|
||||
}
|
||||
}
|
||||
|
||||
+ if (!m_showAddedDuringInhibition && sourceIdx.data(Notifications::WasAddedDuringInhibitionRole).toBool()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
return true;
|
||||
}
|
||||
diff --git a/libnotificationmanager/notificationfilterproxymodel_p.h b/libnotificationmanager/notificationfilterproxymodel_p.h
|
||||
index 4029320e8e..af04a9fac1 100644
|
||||
--- a/libnotificationmanager/notificationfilterproxymodel_p.h
|
||||
+++ b/libnotificationmanager/notificationfilterproxymodel_p.h
|
||||
@@ -30,6 +30,9 @@ public:
|
||||
bool showDismissed() const;
|
||||
void setShowDismissed(bool show);
|
||||
|
||||
+ bool showAddedDuringInhibition() const;
|
||||
+ void setShowAddedDuringInhibition(bool show);
|
||||
+
|
||||
QStringList blacklistedDesktopEntries() const;
|
||||
void setBlackListedDesktopEntries(const QStringList &blacklist);
|
||||
|
||||
@@ -46,6 +49,7 @@ Q_SIGNALS:
|
||||
void urgenciesChanged();
|
||||
void showExpiredChanged();
|
||||
void showDismissedChanged();
|
||||
+ void showAddedDuringInhibitionChanged();
|
||||
void blacklistedDesktopEntriesChanged();
|
||||
void blacklistedNotifyRcNamesChanged();
|
||||
void whitelistedDesktopEntriesChanged();
|
||||
@@ -58,6 +62,7 @@ private:
|
||||
Notifications::Urgencies m_urgencies = Notifications::LowUrgency | Notifications::NormalUrgency | Notifications::CriticalUrgency;
|
||||
bool m_showDismissed = false;
|
||||
bool m_showExpired = false;
|
||||
+ bool m_showAddedDuringInhibition = true;
|
||||
|
||||
QStringList m_blacklistedDesktopEntries;
|
||||
QStringList m_blacklistedNotifyRcNames;
|
||||
diff --git a/libnotificationmanager/notifications.cpp b/libnotificationmanager/notifications.cpp
|
||||
index 9b3e18018b..3d5662f926 100644
|
||||
--- a/libnotificationmanager/notifications.cpp
|
||||
+++ b/libnotificationmanager/notifications.cpp
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <memory>
|
||||
|
||||
#include <KDescendantsProxyModel>
|
||||
+#include <KLocalizedString>
|
||||
+#include <KNotification>
|
||||
|
||||
#include "limitedrowcountproxymodel_p.h"
|
||||
#include "notificationfilterproxymodel_p.h"
|
||||
@@ -30,6 +32,7 @@
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
+using namespace Qt::StringLiterals;
|
||||
using namespace NotificationManager;
|
||||
|
||||
class Q_DECL_HIDDEN Notifications::Private
|
||||
@@ -166,6 +169,7 @@ void Notifications::Private::initProxyModels()
|
||||
connect(filterModel, &NotificationFilterProxyModel::urgenciesChanged, q, &Notifications::urgenciesChanged);
|
||||
connect(filterModel, &NotificationFilterProxyModel::showExpiredChanged, q, &Notifications::showExpiredChanged);
|
||||
connect(filterModel, &NotificationFilterProxyModel::showDismissedChanged, q, &Notifications::showDismissedChanged);
|
||||
+ connect(filterModel, &NotificationFilterProxyModel::showAddedDuringInhibitionChanged, q, &Notifications::showAddedDuringInhibitionChanged);
|
||||
connect(filterModel, &NotificationFilterProxyModel::blacklistedDesktopEntriesChanged, q, &Notifications::blacklistedDesktopEntriesChanged);
|
||||
connect(filterModel, &NotificationFilterProxyModel::blacklistedNotifyRcNamesChanged, q, &Notifications::blacklistedNotifyRcNamesChanged);
|
||||
|
||||
@@ -245,7 +249,7 @@ void Notifications::Private::updateCount()
|
||||
for (int i = 0; i < filterModel->rowCount(); ++i) {
|
||||
const QModelIndex idx = filterModel->index(i, 0);
|
||||
|
||||
- if (idx.data(Notifications::ExpiredRole).toBool()) {
|
||||
+ if (idx.data(Notifications::ExpiredRole).toBool() || idx.data(Notifications::WasAddedDuringInhibitionRole).toBool()) {
|
||||
++expired;
|
||||
} else {
|
||||
++active;
|
||||
@@ -477,6 +481,16 @@ void Notifications::setShowDismissed(bool show)
|
||||
d->filterModel->setShowDismissed(show);
|
||||
}
|
||||
|
||||
+bool Notifications::showAddedDuringInhibition() const
|
||||
+{
|
||||
+ return d->filterModel->showAddedDuringInhibition();
|
||||
+}
|
||||
+
|
||||
+void Notifications::setShowAddedDuringInhibition(bool show)
|
||||
+{
|
||||
+ d->filterModel->setShowAddedDuringInhibition(show);
|
||||
+}
|
||||
+
|
||||
QStringList Notifications::blacklistedDesktopEntries() const
|
||||
{
|
||||
return d->filterModel->blacklistedDesktopEntries();
|
||||
@@ -812,6 +826,28 @@ void Notifications::collapseAllGroups()
|
||||
}
|
||||
}
|
||||
|
||||
+void Notifications::showInhibitionSummary()
|
||||
+{
|
||||
+ int inhibited = 0;
|
||||
+ for (int i = 0, count = d->notificationsAndJobsModel->rowCount(); i < count; ++i) {
|
||||
+ const QModelIndex idx = d->notificationsAndJobsModel->index(i, 0);
|
||||
+ if (!idx.data(Notifications::ReadRole).toBool() && idx.data(Notifications::WasAddedDuringInhibitionRole).toBool()) {
|
||||
+ ++inhibited;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!inhibited) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ KNotification::event(u"inhibitionSummary"_s,
|
||||
+ i18nc("@title", "Unread Notifications"),
|
||||
+ i18nc("@info", "%1 notifications were received while Do Not Disturb was active.", QString::number(inhibited)),
|
||||
+ u"preferences-desktop-notification-bell"_s,
|
||||
+ KNotification::CloseOnTimeout,
|
||||
+ u"libnotificationmanager"_s);
|
||||
+}
|
||||
+
|
||||
QVariant Notifications::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return QSortFilterProxyModel::data(index, role);
|
||||
diff --git a/libnotificationmanager/notifications.h b/libnotificationmanager/notifications.h
|
||||
index edb898988f..ef500b0c7b 100644
|
||||
--- a/libnotificationmanager/notifications.h
|
||||
+++ b/libnotificationmanager/notifications.h
|
||||
@@ -61,6 +61,15 @@ class NOTIFICATIONMANAGER_EXPORT Notifications : public QSortFilterProxyModel, p
|
||||
*/
|
||||
Q_PROPERTY(bool showDismissed READ showDismissed WRITE setShowDismissed NOTIFY showDismissedChanged)
|
||||
|
||||
+ /**
|
||||
+ * Whether to show notifications added during inhibition.
|
||||
+ *
|
||||
+ * If set to @c false, notifications are suppressed even after leaving "Do not disturb" mode.
|
||||
+ *
|
||||
+ * Default is @c true.
|
||||
+ */
|
||||
+ Q_PROPERTY(bool showAddedDuringInhibition READ showAddedDuringInhibition WRITE setShowAddedDuringInhibition NOTIFY showAddedDuringInhibitionChanged)
|
||||
+
|
||||
/**
|
||||
* A list of desktop entries for which no notifications should be shown.
|
||||
*
|
||||
@@ -285,6 +294,8 @@ public:
|
||||
///< notification in a certain way, or group notifications of similar types. @since 5.21
|
||||
ResidentRole, ///< Whether the notification should keep its actions even when they were invoked. @since 5.22
|
||||
TransientRole, ///< Whether the notification is transient and should not be kept in history. @since 5.22
|
||||
+
|
||||
+ WasAddedDuringInhibitionRole, ///< Whether the notification was added while inhibition was active. @since 6.3
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
@@ -371,6 +382,9 @@ public:
|
||||
bool showDismissed() const;
|
||||
void setShowDismissed(bool show);
|
||||
|
||||
+ bool showAddedDuringInhibition() const;
|
||||
+ void setShowAddedDuringInhibition(bool show);
|
||||
+
|
||||
QStringList blacklistedDesktopEntries() const;
|
||||
void setBlacklistedDesktopEntries(const QStringList &blacklist);
|
||||
|
||||
@@ -529,6 +543,11 @@ public:
|
||||
|
||||
Q_INVOKABLE void collapseAllGroups();
|
||||
|
||||
+ /**
|
||||
+ * Shows a notification to report the number of unread inhibited notifications.
|
||||
+ */
|
||||
+ Q_INVOKABLE void showInhibitionSummary();
|
||||
+
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
@@ -541,6 +560,7 @@ Q_SIGNALS:
|
||||
void limitChanged();
|
||||
void showExpiredChanged();
|
||||
void showDismissedChanged();
|
||||
+ void showAddedDuringInhibitionChanged();
|
||||
void blacklistedDesktopEntriesChanged();
|
||||
void blacklistedNotifyRcNamesChanged();
|
||||
void whitelistedDesktopEntriesChanged();
|
||||
diff --git a/libnotificationmanager/server_p.cpp b/libnotificationmanager/server_p.cpp
|
||||
index 84fe37afa9..66cd621033 100644
|
||||
--- a/libnotificationmanager/server_p.cpp
|
||||
+++ b/libnotificationmanager/server_p.cpp
|
||||
@@ -164,6 +164,7 @@ uint ServerPrivate::Notify(const QString &app_name,
|
||||
notification.setActions(actions);
|
||||
|
||||
notification.setTimeout(timeout);
|
||||
+ notification.setWasAddedDuringInhibition(m_inhibited);
|
||||
|
||||
// might override some of the things we set above (like application name)
|
||||
notification.d->processHints(hints);
|
||||
Loading…
Add table
Add a link
Reference in a new issue