[graphics/krita/krita/5.2] libs/ui: [string freeze exception] Fix a crash when trying to clear scrapad while it is busy
Dmitry Kazakov
null at kde.org
Thu Oct 24 13:12:17 BST 2024
Git commit 29c864fe540b918a5b9fd5d86426f81bbbcf8d16 by Dmitry Kazakov.
Committed on 24/10/2024 at 12:11.
Pushed by dkazakov into branch 'krita/5.2'.
[string freeze exception] Fix a crash when trying to clear scrapad while it is busy
BUG:488800
CC:kimageshop at kde.org
CC:kde-i18n-doc at kde.org
M +5 -0 libs/ui/kis_async_action_feedback.cpp
M +24 -0 libs/ui/kis_async_action_feedback.h
M +113 -41 libs/ui/widgets/kis_scratch_pad.cpp
https://invent.kde.org/graphics/krita/-/commit/29c864fe540b918a5b9fd5d86426f81bbbcf8d16
diff --git a/libs/ui/kis_async_action_feedback.cpp b/libs/ui/kis_async_action_feedback.cpp
index 149c90961e0..92df3a694e1 100644
--- a/libs/ui/kis_async_action_feedback.cpp
+++ b/libs/ui/kis_async_action_feedback.cpp
@@ -73,3 +73,8 @@ void KisAsyncActionFeedback::waitForMutexLikeImpl(std::unique_ptr<MutexLikeBase>
mutex->unlock();
}
+
+QString KisAsyncActionFeedback::DefaultWaitingMessageCallback::operator()() const
+{
+ return i18nc("progress dialog message when the user has to wait for the image to become unlocked", "Waiting for the action to complete...");
+}
diff --git a/libs/ui/kis_async_action_feedback.h b/libs/ui/kis_async_action_feedback.h
index 3007e4baa99..6df0f9d734d 100644
--- a/libs/ui/kis_async_action_feedback.h
+++ b/libs/ui/kis_async_action_feedback.h
@@ -16,6 +16,11 @@ class QMutex;
class KisAsyncActionFeedback
{
+private:
+ struct DefaultWaitingMessageCallback {
+ QString operator()() const;
+ };
+
public:
KisAsyncActionFeedback(const QString &message, QWidget *parent);
~KisAsyncActionFeedback();
@@ -28,6 +33,25 @@ public:
waitForMutexLikeImpl(std::make_unique<MutexLike<Mutex>>(mutex));
}
+ template<typename Mutex, typename CallbackFunc = DefaultWaitingMessageCallback>
+ class MutexWrapper : public Mutex
+ {
+ public:
+ template<typename ...Args>
+ MutexWrapper(Args ...args)
+ : Mutex(args...)
+ {
+ }
+
+ void lock() {
+ if (!Mutex::try_lock()) {
+ KisAsyncActionFeedback f(CallbackFunc{}(), 0);
+ f.waitForMutex(static_cast<Mutex&>(*this));
+ Mutex::lock();
+ }
+ }
+ };
+
private:
/**
diff --git a/libs/ui/widgets/kis_scratch_pad.cpp b/libs/ui/widgets/kis_scratch_pad.cpp
index be72890e39d..8be76deee56 100644
--- a/libs/ui/widgets/kis_scratch_pad.cpp
+++ b/libs/ui/widgets/kis_scratch_pad.cpp
@@ -38,6 +38,43 @@
#include "kis_node_graph_listener.h"
#include "kis_transaction.h"
+#include <KisAdaptedLock.h>
+#include <kis_async_action_feedback.h>
+
+namespace {
+class KisUpdateSchedulerLockAdapter
+{
+public:
+ KisUpdateSchedulerLockAdapter(KisUpdateScheduler *scheduler)
+ : m_scheduler(scheduler)
+ {
+ }
+
+ void lock() {
+ m_scheduler->barrierLock();
+ }
+
+ bool try_lock() {
+ return m_scheduler->tryBarrierLock();
+ }
+
+ void unlock() {
+ m_scheduler->unlock();
+ }
+
+private:
+ KisUpdateScheduler *m_scheduler;
+};
+
+/**
+ * Define an adapted lock that has application-wide busy-wait feedback
+ */
+KIS_DECLARE_ADAPTED_LOCK(KisUpdateSchedulerLockWithFeedback,
+ KisAsyncActionFeedback::MutexWrapper<KisUpdateSchedulerLockAdapter>)
+
+}
+
+
class KisScratchPadNodeListener : public KisNodeGraphListener
{
public:
@@ -533,10 +570,15 @@ void KisScratchPad::paintCustomImage(const QImage& loadedImage)
KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace());
device->convertFromQImage(scaledImage, 0);
- KisPainter painter(paintDevice);
- painter.beginTransaction();
- painter.bitBlt(overlayRect.topLeft(), device, imageRect);
- painter.deleteTransaction();
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+ KisPainter painter(paintDevice);
+ painter.beginTransaction();
+ painter.bitBlt(overlayRect.topLeft(), device, imageRect);
+ painter.deleteTransaction();
+ }
+
+
update();
}
@@ -555,10 +597,14 @@ void KisScratchPad::loadScratchpadImage(QImage image)
KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace());
device->convertFromQImage(image, 0);
- KisPainter painter(paintDevice);
- painter.beginTransaction();
- painter.bitBlt(imageSize.topLeft(), device, imageSize);
- painter.deleteTransaction();
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+ KisPainter painter(paintDevice);
+ painter.beginTransaction();
+ painter.bitBlt(imageSize.topLeft(), device, imageSize);
+ painter.deleteTransaction();
+ }
+
update();
}
@@ -586,10 +632,14 @@ void KisScratchPad::paintPresetImage()
KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace());
device->convertFromQImage(scaledImage, 0);
- KisPainter painter(paintDevice);
- painter.beginTransaction();
- painter.bitBlt(overlayRect.topLeft(), device, imageRect);
- painter.deleteTransaction();
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+ KisPainter painter(paintDevice);
+ painter.beginTransaction();
+ painter.bitBlt(overlayRect.topLeft(), device, imageRect);
+ painter.deleteTransaction();
+ }
+
update();
}
@@ -606,10 +656,15 @@ void KisScratchPad::fillDefault()
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
- KisTransaction t(paintDevice);
- paintDevice->setDefaultPixel(m_defaultColor);
- paintDevice->clear();
- t.end();
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+
+ KisTransaction t(paintDevice);
+ paintDevice->setDefaultPixel(m_defaultColor);
+ paintDevice->clear();
+ t.end();
+ }
+
update();
}
@@ -621,10 +676,15 @@ void KisScratchPad::fillTransparent() {
KoColor transparentColor(transQColor, KoColorSpaceRegistry::instance()->rgb8());
transparentColor.setOpacity(0.0);
- KisTransaction t(paintDevice);
- paintDevice->setDefaultPixel(transparentColor);
- paintDevice->clear();
- t.end();
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+
+ KisTransaction t(paintDevice);
+ paintDevice->setDefaultPixel(transparentColor);
+ paintDevice->clear();
+ t.end();
+ }
+
update();
}
@@ -641,21 +701,25 @@ void KisScratchPad::fillGradient()
KoAbstractGradientSP gradient = m_resourceProvider->currentGradient();
QRect gradientRect = widgetToDocument().mapRect(rect());
- KisTransaction t(paintDevice);
-
- paintDevice->clear();
- KisGradientPainter painter(paintDevice);
- painter.setGradient(gradient);
- painter.setGradientShape(KisGradientPainter::GradientShapeLinear);
- painter.paintGradient(gradientRect.topLeft(),
- gradientRect.bottomRight(),
- KisGradientPainter::GradientRepeatNone,
- 0.2, false,
- gradientRect.left(), gradientRect.top(),
- gradientRect.width(), gradientRect.height());
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+ KisTransaction t(paintDevice);
+
+ paintDevice->clear();
+
+ KisGradientPainter painter(paintDevice);
+ painter.setGradient(gradient);
+ painter.setGradientShape(KisGradientPainter::GradientShapeLinear);
+ painter.paintGradient(gradientRect.topLeft(),
+ gradientRect.bottomRight(),
+ KisGradientPainter::GradientRepeatNone,
+ 0.2, false,
+ gradientRect.left(), gradientRect.top(),
+ gradientRect.width(), gradientRect.height());
+ t.end();
+ }
- t.end();
update();
}
@@ -664,10 +728,14 @@ void KisScratchPad::fillBackground()
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
- KisTransaction t(paintDevice);
- paintDevice->setDefaultPixel(m_resourceProvider->bgColor());
- paintDevice->clear();
- t.end();
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+ KisTransaction t(paintDevice);
+ paintDevice->setDefaultPixel(m_resourceProvider->bgColor());
+ paintDevice->clear();
+ t.end();
+ }
+
update();
}
@@ -678,10 +746,14 @@ void KisScratchPad::fillLayer()
QRect sourceRect(0, 0, paintDevice->exactBounds().width(), paintDevice->exactBounds().height());
- KisPainter painter(paintDevice);
- painter.beginTransaction();
- painter.bitBlt(QPoint(0, 0), m_resourceProvider->currentImage()->projection(), sourceRect);
- painter.deleteTransaction();
+ {
+ KisUpdateSchedulerLockWithFeedback l(m_updateScheduler);
+ KisPainter painter(paintDevice);
+ painter.beginTransaction();
+ painter.bitBlt(QPoint(0, 0), m_resourceProvider->currentImage()->projection(), sourceRect);
+ painter.deleteTransaction();
+ }
+
update();
}
More information about the kde-i18n-doc
mailing list