File indexing completed on 2024-05-12 15:58:22

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