File indexing completed on 2024-05-19 04:26:17

0001 /*
0002  *  SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_image_signal_router.h"
0008 
0009 #include <QThread>
0010 #include <KisStaticInitializer.h>
0011 
0012 #include "kis_image.h"
0013 
0014 
0015 #define CONNECT_TO_IMAGE(signal)                                        \
0016     connect(this, SIGNAL(signal), m_image, SIGNAL(signal), Qt::DirectConnection)
0017 
0018 #define CONNECT_TO_IMAGE_QUEUED(signal)                                 \
0019     connect(this, SIGNAL(signal), m_image, SIGNAL(signal), Qt::QueuedConnection)
0020 
0021 KIS_DECLARE_STATIC_INITIALIZER {
0022     qRegisterMetaType<KisImageSignalType>("KisImageSignalType");
0023 }
0024 
0025 
0026 KisImageSignalRouter::KisImageSignalRouter(KisImageWSP image)
0027     : QObject(image.data()),
0028       m_image(image)
0029 {
0030     connect(this, SIGNAL(sigNotification(KisImageSignalType)),
0031             SLOT(slotNotification(KisImageSignalType)));
0032 
0033     CONNECT_TO_IMAGE(sigImageModified());
0034     CONNECT_TO_IMAGE(sigImageModifiedWithoutUndo());
0035     CONNECT_TO_IMAGE(sigSizeChanged(const QPointF&, const QPointF&));
0036     CONNECT_TO_IMAGE(sigResolutionChanged(double, double));
0037     CONNECT_TO_IMAGE(sigRequestNodeReselection(KisNodeSP, const KisNodeList&));
0038 
0039     CONNECT_TO_IMAGE(sigNodeChanged(KisNodeSP));
0040     CONNECT_TO_IMAGE(sigNodeAddedAsync(KisNodeSP));
0041     CONNECT_TO_IMAGE(sigRemoveNodeAsync(KisNodeSP));
0042     CONNECT_TO_IMAGE(sigLayersChangedAsync());
0043 
0044     /**
0045      * Color space and profile conversion functions run without strokes,
0046      * therefore they are executed in GUI hread under the global lock held.
0047      *
0048      * To ensure that the receiver of the signal will not deadlock by
0049      * barrier-locking the image, we should make these signals queued.
0050      */
0051 
0052     CONNECT_TO_IMAGE_QUEUED(sigProfileChanged(const KoColorProfile*));
0053     CONNECT_TO_IMAGE_QUEUED(sigColorSpaceChanged(const KoColorSpace*));
0054 }
0055 
0056 KisImageSignalRouter::~KisImageSignalRouter()
0057 {
0058 }
0059 
0060 void KisImageSignalRouter::emitImageModifiedNotification()
0061 {
0062     emit sigImageModified();
0063 }
0064 
0065 void KisImageSignalRouter::emitNotifications(KisImageSignalVector notifications)
0066 {
0067     Q_FOREACH (const KisImageSignalType &type, notifications) {
0068         emitNotification(type);
0069     }
0070 }
0071 
0072 void KisImageSignalRouter::emitNotification(KisImageSignalType type)
0073 {
0074     /**
0075      * All the notifications except LayersChangedSignal should go in a
0076      * queued way. And LayersChangedSignal should be delivered to the
0077      * recipients in a non-reordered way
0078      */
0079 
0080     if (type.id == LayersChangedSignal ||
0081         type.id == NodeReselectionRequestSignal) {
0082         slotNotification(type);
0083     } else {
0084         emit sigNotification(type);
0085     }
0086 }
0087 
0088 void KisImageSignalRouter::emitNodeChanged(KisNodeSP node)
0089 {
0090     emit sigNodeChanged(node);
0091 }
0092 
0093 void KisImageSignalRouter::emitNodeHasBeenAdded(KisNode *parent, int index)
0094 {
0095     KisNodeSP newNode = parent->at(index);
0096 
0097     // overlay selection masks reset frames themselves
0098     if (!newNode->inherits("KisSelectionMask")) {
0099         KisImageSP image = m_image.toStrongRef();
0100         if (image) {
0101             image->invalidateAllFrames();
0102         }
0103     }
0104 
0105     emit sigNodeAddedAsync(newNode);
0106 }
0107 
0108 void KisImageSignalRouter::emitAboutToRemoveANode(KisNode *parent, int index)
0109 {
0110     KisNodeSP removedNode = parent->at(index);
0111 
0112     // overlay selection masks reset frames themselves
0113     if (!removedNode->inherits("KisSelectionMask")) {
0114         KisImageSP image = m_image.toStrongRef();
0115         if (image) {
0116             image->invalidateAllFrames();
0117         }
0118     }
0119 
0120     emit sigRemoveNodeAsync(removedNode);
0121 }
0122 
0123 void KisImageSignalRouter::emitRequestLodPlanesSyncBlocked(bool value)
0124 {
0125     emit sigRequestLodPlanesSyncBlocked(value);
0126 }
0127 
0128 void KisImageSignalRouter::emitNotifyBatchUpdateStarted()
0129 {
0130     emit sigNotifyBatchUpdateStarted();
0131 }
0132 
0133 void KisImageSignalRouter::emitNotifyBatchUpdateEnded()
0134 {
0135     emit sigNotifyBatchUpdateEnded();
0136 }
0137 
0138 void KisImageSignalRouter::slotNotification(KisImageSignalType type)
0139 {
0140     KisImageSP image = m_image.toStrongRef();
0141     if (!image) {
0142         return;
0143     }
0144 
0145     switch(type.id) {
0146     case LayersChangedSignal:
0147         image->invalidateAllFrames();
0148         emit sigLayersChangedAsync();
0149         break;
0150     case ModifiedWithoutUndoSignal:
0151         emit sigImageModifiedWithoutUndo();
0152         break;
0153     case SizeChangedSignal:
0154         image->invalidateAllFrames();
0155         emit sigSizeChanged(type.sizeChangedSignal.oldStillPoint,
0156                             type.sizeChangedSignal.newStillPoint);
0157         break;
0158     case ProfileChangedSignal:
0159         image->invalidateAllFrames();
0160         emit sigProfileChanged(image->profile());
0161         break;
0162     case ColorSpaceChangedSignal:
0163         image->invalidateAllFrames();
0164         emit sigColorSpaceChanged(image->colorSpace());
0165         break;
0166     case ResolutionChangedSignal:
0167         image->invalidateAllFrames();
0168         emit sigResolutionChanged(image->xRes(), image->yRes());
0169         break;
0170     case NodeReselectionRequestSignal:
0171         if (type.nodeReselectionSignal.newActiveNode ||
0172             !type.nodeReselectionSignal.newSelectedNodes.isEmpty()) {
0173 
0174             emit sigRequestNodeReselection(type.nodeReselectionSignal.newActiveNode,
0175                                            type.nodeReselectionSignal.newSelectedNodes);
0176         }
0177         break;
0178     }
0179 }