1 /*
2 * Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 #include "KisBusyWaitBroker.h"
19
20 #include <QGlobalStatic>
21 #include <QMutex>
22 #include <QMutexLocker>
23
24 #include <QThread>
25 #include <QApplication>
26
27 #include "kis_image.h"
28
29
30 Q_GLOBAL_STATIC(KisBusyWaitBroker, s_instance)
31
32
33 struct KisBusyWaitBroker::Private
34 {
35 QMutex lock;
36 QHash<KisImage*, int> waitingOnImages;
37 int guiThreadLockCount = 0;
38
39 std::function<void(KisImageSP)> feedbackCallback;
40 };
41
42
KisBusyWaitBroker()43 KisBusyWaitBroker::KisBusyWaitBroker()
44 : m_d(new Private)
45 {
46 }
47
~KisBusyWaitBroker()48 KisBusyWaitBroker::~KisBusyWaitBroker()
49 {
50 }
51
instance()52 KisBusyWaitBroker *KisBusyWaitBroker::instance()
53 {
54 return s_instance;
55 }
56
notifyWaitOnImageStarted(KisImage * image)57 void KisBusyWaitBroker::notifyWaitOnImageStarted(KisImage* image)
58 {
59 if (QThread::currentThread() != qApp->thread()) return;
60
61 bool needsStartCallback = false;
62
63 {
64 QMutexLocker l(&m_d->lock);
65
66 m_d->guiThreadLockCount++;
67 m_d->waitingOnImages[image]++;
68
69 needsStartCallback = m_d->waitingOnImages[image] == 1;
70 }
71
72 if (m_d->feedbackCallback && needsStartCallback && image->refCount()) {
73 m_d->feedbackCallback(image);
74 }
75 }
76
notifyWaitOnImageEnded(KisImage * image)77 void KisBusyWaitBroker::notifyWaitOnImageEnded(KisImage* image)
78 {
79 if (QThread::currentThread() != qApp->thread()) return;
80
81 {
82 QMutexLocker l(&m_d->lock);
83 m_d->guiThreadLockCount--;
84
85 m_d->waitingOnImages[image]--;
86 KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->waitingOnImages[image] >= 0);
87
88 if (m_d->waitingOnImages[image] == 0) {
89 m_d->waitingOnImages.remove(image);
90 }
91 }
92 }
93
notifyGeneralWaitStarted()94 void KisBusyWaitBroker::notifyGeneralWaitStarted()
95 {
96 if (QThread::currentThread() != qApp->thread()) return;
97
98 QMutexLocker l(&m_d->lock);
99 m_d->guiThreadLockCount++;
100 }
101
notifyGeneralWaitEnded()102 void KisBusyWaitBroker::notifyGeneralWaitEnded()
103 {
104 if (QThread::currentThread() != qApp->thread()) return;
105
106 QMutexLocker l(&m_d->lock);
107 m_d->guiThreadLockCount--;
108 }
109
setFeedbackCallback(std::function<void (KisImageSP)> callback)110 void KisBusyWaitBroker::setFeedbackCallback(std::function<void (KisImageSP)> callback)
111 {
112 m_d->feedbackCallback = callback;
113 }
114
guiThreadIsWaitingForBetterWeather() const115 bool KisBusyWaitBroker::guiThreadIsWaitingForBetterWeather() const
116 {
117 return m_d->guiThreadLockCount;
118 }
119
120
121